■ 入力キャプチャー
キャプチャー機能は入力端子からの信号をトリガー信号としてトリガー信号入力時のタイマ値をハード的に記憶する
機能です。キャプチャー用の入力端子及びタイマは以下のようになっています。dsPICはトリガー入力端子の名称が
CCPxからICx(Input Capture x)に変更になっています。また、FIFOバッファーが4つあります。FIFOバッファーが空に
なっていないと割込みがかからないので読込みの際はバッファーを空にしておく必要があります。
PICの種類 | トリガー入力端子名称 | タイマ | 時間測定用外部クロック 入力端子 |
FIFOバッファー |
PIC16 | CCPx (例 CCP1、CCP2) | タイマ1 | TxCKI (例 T1CKI) | 1 |
PIC18 | CCPx (例 CCP1、CCP3) | タイマ1またはタイマ3 | TxCKI (例 T1CKI) | 1 |
dsPIC | ICx (例 IC1、IC5) | タイマ2またはタイマ3 | - | 4 |
以下にキャプチャーを使った例を紹介します。
(1) ストップウォッチ <CCS編>
(2) 連続矩形波のパルス幅測定 <CCS編> <dsPIC編>
(3) 電波時計
★ 時刻符号(タイムコード)生成 <CCS編>
★ 時刻符号(タイムコード)解読
<dsPIC編>
(1)ストップウォッチ <CCS編>
<試作品仕様>
・スタート/ストップボタンを押すと計測を開始する。
・計測中にスタート/ストップボタンを押すと計測を完了し経過時間を液晶に表示する。
・液晶表示は単位secで少数点以下の有効数字は1桁とする。 (例)Time=5.6sec
・リセットボタンを押すとリセットされ液晶の表示が”Time=0.0sec”に戻る。
・時間の計測は10Hzの外部クロックを使用すること。
<試作品回路図>(→回路図のPDFファイル)
PIC18F452をつかった場合の回路図を以下に示します。
<試作品外観>下記の写真には上記回路図にはない、また本テーマと関係のない部品が多々写っています
<プログラム例>
//*********************************************************************************** // ストップウォッチ <CCS編> //*********************************************************************************** #include "18f452.h" #use delay(clock=10000000) // 10MHz(システムクロック周波数) #FUSES HS,NOWDT,NOPROTECT,PUT,BROWNOUT,NOLVP #use fast_io(D) //////// Port define and link LCD library #define mode 0 // 液晶 #define input_x input_D #define output_x output_D #define set_tris_x set_tris_D #define rs PIN_D2 //rs #define stb PIN_D0 //strobe #include <1lcd_lib.c> int Watch_Mode = 0; unsigned long int Start_time,Stop_time,Count; float Time = 0; #int_CCP1 //リセットスイッチ信号立下り 割込み void Capture1(void) { Watch_Mode = 0; //非計測時 lcd_clear(); Time = 0.0; printf(lcd_data,"Time=%5.1fsec",Time); } #int_CCP2 //スタート/ストップ信号立下り 割込み void Capture2(void) { if(Watch_Mode == 0) //非計測時 { Start_time = CCP_2; Watch_Mode = 1; } else //計測時 { Stop_time = CCP_2; Watch_Mode = 0; Count = Stop_time - Start_time; Time = (float)Count /10; lcd_clear(); printf(lcd_data,"Time=%5.1fsec",Time); } } main(){ setup_ccp1(CCP_CAPTURE_FE); //立下りでトリガ setup_CCP2(CCP_CAPTURE_FE); //立下りでトリガ setup_timer_1(T1_EXTERNAL_SYNC | T1_DIV_BY_1); //外部クロック使用内部クロックと同期させる //同期させないと読み出している最中にカウントアップしてしまう //外部クロック 10Hz (at T1CKI/RC0) lcd_init(); lcd_cmd(0b00001100); // カーソル:OFF ブリンク:OFF lcd_clear(); printf(lcd_data,"Stop Watch !!"); delay_ms(2000); enable_interrupts(INT_CCP1); enable_interrupts(INT_CCP2); enable_interrupts(GLOBAL); while(1) //CCP割込みを待つ { } return 0; } //--------------------------------------------------------------------------- //************************************** //インクルードファイル 1lcd_lib.c //このファイルは後閑哲也さんが設計されたものです //************************************** /////////////////////////////////////////////// // 液晶表示器制御ライブラリ // 内蔵関数は以下 // lcd_init() ----- 初期化 // lcd_cmd(cmd) ----- コマンド出力 // lcd_data(chr) ----- 1文字表示出力 // lcd_clear() ----- 全消去 //////// データ出力サブ関数 void lcd_out(int code, int flag) { output_x((code & 0xF0) | (input_x() & 0x0F)); if (flag == 0) output_high(rs); //表示データの場合 else output_low(rs); //コマンドデータの場合 delay_cycles(4); //NOP 1 output_high(stb); //strobe out delay_cycles(8); //NOP 2 output_low(stb); //reset strobe } //////// 1文字表示関数 void lcd_data(int asci) { lcd_out(asci, 0); //上位4ビット出力 lcd_out(asci<<4, 0); //下位4ビット出力 delay_us(50); //50μsec待ち } /////// コマンド出力関数 void lcd_cmd(int cmd) { lcd_out(cmd, 1); //上位4ビット出力 lcd_out(cmd<<4, 1); //下位4ビット出力 delay_ms(2); //2msec待ち } /////// 全消去関数 void lcd_clear() { lcd_cmd(0x01); //初期化コマンド出力 delay_ms(15); //15msec待ち } /////// 初期化関数 void lcd_init() { set_tris_x(mode); //モードセット delay_ms(15); lcd_out(0x30, 1); //8bit mode set delay_ms(5); lcd_out(0x30, 1); //8bit mode set delay_ms(1); lcd_out(0x30, 1); //8bit mode set delay_ms(1); lcd_out(0x20, 1); //4bit mode set delay_ms(1); lcd_cmd(0x2E); //DL=0 4bit mode lcd_cmd(0x08); //display off C=D=B=0 lcd_cmd(0x0D); //display on C=D=1 B=0 lcd_cmd(0x06); //entry I/D=1 S=0 lcd_cmd(0x02); //cursor home }
<動作結果>
市販のストップウォッチと同時に約10秒間 Start/Stop動作させた時の写真です。左側が動作前で右側が動作後の
写真です。 外部クロックはファンクションジェネレータ(GW INSTEC SFG-2104)からの10Hz矩形波です。
動作前 | 約10秒動作後 | |
(2)連続矩形波のパルス幅測定
<CCS編>
<試作品仕様>
・ CCP1、CCP2 キャプチャー入力端子に入力された矩形波のHighレベル時のパルス幅を測定し液晶の1行目に
表示する。
・ 液晶の2行目には内部クロックのカウント数を表示する。 (例) Count=333
<試作品回路図>(→回路図のPDFファイル)
PIC18F452を使った例を紹介します。
<試作品外観>下記の写真には上記回路図にはない、また本テーマと関係のない部品が多々写っています
<プログラム例> //*********************************************************************************** //パルス幅測定 <CCS編> //CCP1 : パルス立ち上がり //CCP2 : パルス立下り //*********************************************************************************** #include "18f452.h" #use delay(clock=10000000) // 10MHz(システムクロック周波数) #FUSES HS,NOWDT,NOPROTECT,PUT,BROWNOUT,NOLVP #use fast_io(D) //////// Port define and link LCD library #define mode 0 // 液晶 #define input_x input_D #define output_x output_D #define set_tris_x set_tris_D #define rs PIN_D2 //rs #define stb PIN_D0 //strobe #include <1lcd_lib.c> unsigned long int rise,fall,pulse_Count; float pulse_width; #int_CCP2 //リセットスイッチ動作時 void interval(void) { disable_interrupts(INT_CCP2); // Setup interrupt on falling edge disable_interrupts(GLOBAL); rise = CCP_1; //パルス波形立ち上がり時のタイマ1のカウント数 fall = CCP_2; //パルス波形立ち下り時のタイマ1のカウント数 pulse_Count = fall - rise; pulse_width = (float)pulse_Count*0.4; //単位[μsec] 1カウント=0.4μsec lcd_clear(); printf(lcd_data,"Time=%5.1fusec",pulse_width); lcd_cmd(0xC0);//2行目の先頭へ printf(lcd_data,"Count=%lu",pulse_Count); delay_ms(1000); enable_interrupts(INT_CCP2); // Setup interrupt on falling edge enable_interrupts(GLOBAL); } main(){ setup_ccp1(CCP_CAPTURE_RE); //立上がりでトリガ setup_CCP2(CCP_CAPTURE_FE); //立下りでトリガ setup_timer_1(T1_INTERNAL); //内部クロック使用 //同期させないと読み出している最中にカウントアップしてしまう lcd_init(); lcd_cmd(0b00001100); // カーソル:OFF ブリンク:OFF lcd_clear(); printf(lcd_data,"Stop Watch !!"); delay_ms(2000); lcd_clear(); printf(lcd_data,"Time=%5.1fusec",pulse_width); enable_interrupts(INT_CCP2); // Setup interrupt on falling edge enable_interrupts(GLOBAL); while(1) //CCP割込みを待つ { } return 0; } //--------------------------------------------------------------------------- //************************************** //インクルードファイル 1lcd_lib.c //このファイルは後閑哲也さんが設計されたものです //************************************** /////////////////////////////////////////////// // 液晶表示器制御ライブラリ // 内蔵関数は以下 // lcd_init() ----- 初期化 // lcd_cmd(cmd) ----- コマンド出力 // lcd_data(chr) ----- 1文字表示出力 // lcd_clear() ----- 全消去 //////// データ出力サブ関数 void lcd_out(int code, int flag) { output_x((code & 0xF0) | (input_x() & 0x0F)); if (flag == 0) output_high(rs); //表示データの場合 else output_low(rs); //コマンドデータの場合 delay_cycles(4); //NOP 1 output_high(stb); //strobe out delay_cycles(8); //NOP 2 output_low(stb); //reset strobe } //////// 1文字表示関数 void lcd_data(int asci) { lcd_out(asci, 0); //上位4ビット出力 lcd_out(asci<<4, 0); //下位4ビット出力 delay_us(50); //50μsec待ち } /////// コマンド出力関数 void lcd_cmd(int cmd) { lcd_out(cmd, 1); //上位4ビット出力 lcd_out(cmd<<4, 1); //下位4ビット出力 delay_ms(2); //2msec待ち } /////// 全消去関数 void lcd_clear() { lcd_cmd(0x01); //初期化コマンド出力 delay_ms(15); //15msec待ち } /////// 初期化関数 void lcd_init() { set_tris_x(mode); //モードセット delay_ms(15); lcd_out(0x30, 1); //8bit mode set delay_ms(5); lcd_out(0x30, 1); //8bit mode set delay_ms(1); lcd_out(0x30, 1); //8bit mode set delay_ms(1); lcd_out(0x20, 1); //4bit mode set delay_ms(1); lcd_cmd(0x2E); //DL=0 4bit mode lcd_cmd(0x08); //display off C=D=B=0 lcd_cmd(0x0D); //display on C=D=1 B=0 lcd_cmd(0x06); //entry I/D=1 S=0 lcd_cmd(0x02); //cursor home }
<動作結果>
入力信号としてDuty=50%の 500Hzと2KHzの矩形波をCPP1、CPP2に入力した時の液晶画面の写真を示します。
TimeはパルスがHighの時間幅 [単位:μsec] です。
尚、入力パルスはファンクションジェネレータ(GW INSTEC SFG-2104)からの矩形波です
500Hz入力時 | 2KHz入力時 | |
<dsPIC編> PIC30F2012
<試作品仕様>
・ IC1、IC2 キャプチャー入力端子に入力された矩形波の周期を液晶の1行目に表示する。
(例) T0=300usec
・ 2行目にはパルスのHighレベル時の時間幅を測定し表示する。
(例) T1=100usec
<試作品回路図>(→回路図のPDFファイル)
dsPIC30F2012を使った例を紹介します。
<試作品外観>下記の写真には上記回路図にはない、また本テーマと関係のない部品が多々写っています
<プログラム例> <dsPIC編> ///************************************************************/ //* インプットキャプチャーによる周期、パルス幅検出 //* dsPIC30F2012 //************************************************************/ // MPLAB プロジェクトへの追加ファイル // Linker Scriptフォルダ p30f2012.gld // Library Filesフォルダ lib30F2012-coff.a #include "p30f2012.h" #include <stdio.h> #include <InCap.h> #include <timer.h> #include "1lcd_lib_C30.h" _FOSC(CSW_FSCM_OFF & // クロック切り替えなし、フェースセイフクロックモニタなし XT_PLL8 //外部発振子:10MHz、PLL:8倍 → システムクロック周波数=10×8=80MHz ); _FWDT(WDT_OFF); _FBORPOR(PBOR_ON & //ブラウンアウトリセット機能:ON BORV_42 & //ブラウンアウト電圧:4.2V PWRT_64 & //パワーオンリセットタイマ64msec MCLR_EN //MCLR機能:ON ); _FGS(CODE_PROT_OFF); //コードプロテクト:OFF int Ver = 789,Count=0; char Buf1[21]; //文字列のバッファー用レジスタ unsigned int FirstEdge_Rise,SecondEdge_Rise,FirstEdge_Fall,T0,T1,dumy; char dumyC; void delay_ms(unsigned int); void delay_ms(unsigned int N) //ウェイト関数 { __delay32(Clock/4000*N); } void _ISR _IC2Interrupt(void) //2回の立ち上がりエッジ毎に割込み発生 { ReadCapture1(&FirstEdge_Fall); ReadCapture2(&FirstEdge_Rise); ReadCapture2(&SecondEdge_Rise); T0 =(unsigned int) (((float)(SecondEdge_Rise - FirstEdge_Rise))*0.4); // パルスの周期 // カウントクロックの周期(1/Fosc×4) ΔT = 1/80 ×4×8(プリスケーラ) =0.4μsec T1 =(unsigned int) (((float)(FirstEdge_Rise - FirstEdge_Fall))*0.4); //パルスのHigh(1)の時間 do { ReadCapture2(&dumy); //FIFOバッファクリア → FIFOバッファが空(IC2CONbits.ICBNE=0)に }while(IC2CONbits.ICBNE); //ならないと次の割り込みはかからない TMR2 = 0; //タイマ2のカウント値リセット→0 IFS0bits.IC2IF = 0; // } /// メイン関数 int main(void) { TRISB = 0; TRISF = 0; TRISD = 0xFFFF; dumyC =' '; ConfigIntCapture2(IC_INT_PRIOR_5 & IC_INT_ON); // IPC1bits.IC2IP = 5; OpenTimer2(T2_ON & T2_GATE_OFF & T2_PS_1_8 & T2_SOURCE_INT, 65000-1); //動作モード設定レジスタ IC2CONの設定 OpenCapture1(IC_IDLE_STOP & //Idle時停止 IC_TIMER2_SRC & //タイマ2で測定 IC_INT_2CAPTURE & //キャプチャー2回で割込み発生 IC_EVERY_FALL_EDGE //立ち下がりエッジ毎にキャプチャー ); OpenCapture2(IC_IDLE_STOP & //Idle時停止 IC_TIMER2_SRC & //タイマ2で測定 IC_INT_2CAPTURE & //キャプチャー2回で割込み発生 IC_EVERY_RISE_EDGE //立ち上がりエッジ毎にキャプチャー ); lcd_init(); // LCD初期化 lcd_cmd(0b00001100); // カーソル:OFF ブリンク:OFF lcd_clear(); // 全消去 sprintf(Buf1,"Capture %d",Ver); //arguementがないと遅い C30のバグ? lcd_str(Buf1); //液晶表示 delay_ms(1000); EnableIntIC2; //割込み許可 IEC0bits.IC2IE = 1; while(1) //Capture割込みを待つ { lcd_clear(); //液晶表示 sprintf(Buf1,"T0=%uusec",T0); // lcd_str(Buf1); lcd_cmd(0xC0); //2行目の先頭へ sprintf(Buf1,"T1=%uusec",T1); //文字列としてバッファーに収納 lcd_str(Buf1); Count++; delay_ms(1000); } CloseCaptre2(); return 0; } //********************************************************************************************* //インクルードファイル 1lcd_lib_C30.h //このファイルは後閑哲也さんが設計されたCCSコンパイラ用液晶表示ライブラリ 1lcd_lib.cをもとに、 //C30コンパイラ対応、及び分散ポート対応等で変更を加えたものです。 //********************************************************************************************* #include "p30f4013.h" #define Clock 80000000 // 単位はHzで指定 // LCDポート設定 #define lcd_port_DB7 LATBbits.LATB12 //LCDのDB7(14番ピン)に接続されるPIC側ポート番号設定 #define lcd_port_DB6 LATBbits.LATB11 //LCDのDB6(13番ピン)に接続されるPIC側ポート番号設定 #define lcd_port_DB5 LATBbits.LATB10 //LCDのDB5(12番ピン)に接続されるPIC側ポート番号設定 #define lcd_port_DB4 LATBbits.LATB9 //LCDのDB4(11番ピン)に接続されつPIC側ポート番号設定 #define lcd_stb LATFbits.LATF0 //LCDのstb(6番ピン)に接続されるPIC側ポート番号設定 #define lcd_rs LATFbits.LATF1 //LCDのrs(4番ピン)に接続されるPIC側ポート番号設定 void lcd_out(char code, char flag); void lcd_data(char asci); void lcd_cmd(char cmd); void lcd_clear(void); void lcd_init(void); void lcd_str(char *str); //******************************************************************************************** //インクルードファイル 1lcd_lib_C30.c //このファイルは後閑哲也さんが設計されたCCSコンパイラ用液晶表示ライブラリ 1lcd_lib.cをもとに、 //C30コンパイラ対応、及び分散ポート対応等で変更を加えたものです。 //******************************************************************************************** /////////////////////////////////////////////// // 液晶表示器制御ライブラリ for C30コンパイラー // 内蔵関数は以下 // lcd_init() ----- 初期化 // lcd_cmd(cmd) ----- コマンド出力 // lcd_data(chr) ----- 1文字表示出力 // lcd_clear() ----- 全消去 // lcd_str(str*) ----- 文字列表示 ////////////////////////////////////////////// #include "1lcd_lib_C30.h" unsigned int _1usec; // 1μsec待つに必要なウェイト回数 unsigned int _50usec; //50μsec待つに必要なウェイト回数 unsigned long N_msec; // 1msec待つに必要なウェイト回数 //////// データ出力サブ関数 void lcd_out(char code, char flag) { if(code & 0b10000000)lcd_port_DB7 = 1; //LCDのDB7への出力セット else lcd_port_DB7 = 0; if(code & 0b01000000)lcd_port_DB6 = 1; //LCDのDB6への出力セット else lcd_port_DB6 = 0; if(code & 0b00100000)lcd_port_DB5 = 1; //LCDのDB5への出力セット else lcd_port_DB5 = 0; if(code & 0b00010000)lcd_port_DB4 = 1; //LCDのDB4への出力セット else lcd_port_DB4 = 0; if (flag == 0) lcd_rs = 1; // 表示データの場合 else lcd_rs = 0; // コマンドデータの場合 __delay32(_1usec); //1μsecウェイト lcd_stb = 1; // strobe(E) ON (Enable) __delay32(_1usec); // 1μsec : strobe信号の幅 lcd_stb = 0; // reset strobe } //////// 1文字表示関数 void lcd_data(char asci) { lcd_out(asci, 0); // 上位4ビット出力 lcd_out(asci<<4, 0); // 下位4ビット出力 __delay32(_50usec); //50μsecウェイト } /////// コマンド出力関数 void lcd_cmd(char cmd) { lcd_out(cmd, 1); // 上位4ビット出力 lcd_out(cmd<<4, 1); // 下位4ビット出力 if((cmd & 0x03) != 0) // clear Homeの場合 __delay32(2*N_msec); // 2msec待ち else __delay32(_50usec); //50μsecウェイト } /////// 全消去関数 void lcd_clear(void) { lcd_cmd(0x01); // 初期化コマンド出力 // __delay32(15*N_msec); //15msecウェイト } /////// 文字列出力関数 void lcd_str(char* str) { while(*str) //文字列終端の '\0'を検出するまで { lcd_data(*str); // 1文字表示 str++; //ポインタをインクリメント } } /////// 初期化関数 void lcd_init(void) { _1usec =(unsigned int)( Clock / 4000000); // 1μsecに要するウェイト回数 //__delay32(N) : Nが11以下の場合でも11回ウェイト _50usec = (unsigned int)(Clock / 4000000 * 50); //50μescに要するウェイト回数 N_msec = (unsigned long int)(Clock / 4000); // 1msecに要するウェイト回数 // = Clock / 4000000*1000 __delay32(20*N_msec); //20msecウェイト lcd_out(0x30, 1); // 8bit mode set __delay32(5*N_msec); //5msecウェイト lcd_out(0x30, 1); // 8bit mode set __delay32(N_msec); //1msecウェイト lcd_out(0x30, 1); // 8bit mode set __delay32(N_msec); //1msecウェイト lcd_out(0x20, 1); // 4bit mode set __delay32(N_msec); //1msecウェイト lcd_cmd(0x2E); // DL=0 4bit mode lcd_cmd(0x08); // display off C=D=B=0 lcd_cmd(0x0D); // display on C=D=1 B=0 lcd_cmd(0x06); // entry I/D=1 S=0 lcd_cmd(0x02); // cursor home }
<動作結果>
IC1、IC2からの入力パルス(Duty=50%)が1KHz、2KHz、4KHzの時の液晶画面の写真を以下に示します
入力パルスはファンクションジェネレータ(INSTEC SFG-2104)からの矩形波です。
1KHz | 2KHZ | 4KHz | ||
(3)電波時計
★ 時刻符号(タイムコード)生成
PICでタイムコードを生成した例を紹介します。
<試作品仕様>
・ JJYと同仕様のタイムコードを生成する。
・ 出力しているタイムコード情報を液晶に表示する。
・ 出力する 年月日時分秒をスイッチで設定できる。
<試作品回路図>(→回路図のPDFファイル)
PIC18F4550を使った例を紹介します。
<試作品外観>下記の写真には上記回路図にはない、また本テーマと関係のない部品が多々写っています。
左側の液晶が載った基板は 電波時計Ver.2 キット(製造元:(有)トライステート 販売元:秋月電子通商)
のタイムコード解読・表示基板です。
<プログラム例> <CCS編> //***************************************************************************** //JJY 電波時計用タイムコード // 生成プログラム PIC18F4550 //***************************************************************************** #include <18F4550.h> #use delay(clock=20000000) #FUSES HS,PUT,NOWDT,BROWNOUT,BORV43,NOPROTECT,NOLVP //////// Port define and link LCD library #define mode 0 #define input_x input_D #define output_x output_D #define set_tris_x set_tris_D #define rs PIN_D2 //chip select #define stb PIN_D0 //strobe #include "1lcd_lib.c" long int Count_25msec = 0,Count_100msec = 0; signed long int Sec = 0,Min = 0,H = 0,Week,Month = 11; unsigned long int Day = 3,Year = 2007; int32 Day_total,Day_Year,Day_This_Year; unsigned long int Day1,Day2,Day3,Day4,Day5,Day6,Day7,Day8,Day9,Day10,Day11,Day12; //Year年の1月1日から各月までの日数累計 short int OutputMode = 1; //1:タイムコード出力モード 0:年月日時分秒 設定モード int swCount_Mode = 0,swCount_Select = 0,swCount_Up = 0,swCount_Down = 0; int SelectMode = 0; // 設定モード → 0:年 1:月 2:日 3:時 4:分 その他:秒 char Sun[] = "Sun."; char Mon[] = "Mon."; char Thues[] = "Thues."; char Wed[] = "Wed."; char Thurs[] = "Thurs."; char Fri[] = "Fri."; char Sat[] = "Sat."; char str[]; char str_Mode[10]; int Out = 0,PAm,PAh; void WeekFunc() //Year、Month、Dayから この日が何曜日かを求める関数 { unsigned long int i,Year1,Day_Feb,Weekx; // 2000年から(Year -1)年までの日数計算----------------------------------------------------- Day_Year = 0; for(i = 2000; i < Year; i++) { if((((i % 4) == 0) && ((i % 100) != 0)) || //100で割り切れないで4で割れる西暦年はうるう年である。 ((i % 900) == 200) || //但し、900で割った時あまりが200または、600の西暦年も ((i % 900) == 600)) //うるう年である。(改定ユリウス暦) { Year1 = 366; } else Year1 = 365; Day_Year = Day_Year + (int32)Year1; } //Year年の累計日数計算----------------------------------------------------------------------- //2月の日数計算 if((((Year % 4) == 0) && ((Year % 100) != 0)) || //100で割り切れないで4で割れる西暦年はうるう年である。 ((Year % 900) == 200) || //但し、900で割った時あまりが200または、600の西暦年も ((Year % 900) = //うるう年である。(改定ユリウス暦) { Day_Feb = 29; } else Day_Feb = 28; Day1 = Day; Day2 = Day1 + 31; Day3 = Day2 + Day_Feb; Day4 = Day3 + 31; Day5 = Day4 + 30; Day6 = Day5 + 31; Day7 = Day6 + 30; Day8 = Day7 + 31; Day9 = Day8 + 31; Day10 = Day9 + 30; Day11 = Day10 + 31; Day12 = Day11 + 30; switch(Month) { case 1: //1月の場合 Day_This_Year = Day1; break; case 2: //2月の場合 Day_This_Year = Day2; break; case 3: Day_This_Year = Day3; //3月の場合 break; case 4: Day_This_Year = Day4; //4月の場合 break; case 5: Day_This_Year = Day5; //5月の場合 break; case 6: Day_This_Year = Day6; //6月の場合 break; case 7: Day_This_Year = Day7; //7月の場合 break; case 8: Day_This_Year = Day8; //8月の場合 break; case 9: Day_This_Year = Day9; //9月の場合 break; case 10: Day_This_Year = Day10; //10月の場合 break; case 11: Day_This_Year = Day11; //11月の場合 break; case 12: Day_This_Year = Day12; //12月の場合 break; default: break; } //2000年1月1日(土)から Year年Month月Day日間での累計日数Day_total ---------------------------------------- Day_total = Day_This_Year + Day_Year; // Year年の累計日数 + 2000年1月1日から ( Year - 1)年12月31日までの日数累計 Weekx = (unsigned long int)( Day_total % 7); switch(Weekx) { case 0: //金曜日 str = Fri; Week = 5; break; case 1: //土曜日 str = Sat; Week = 6; break; case 2: //日曜日 str = Sun; Week = 0; break; case 3: //月曜日 str = Mon; Week = 1; break; case 4: //火曜日 str = Thues; Week= 2; break; case 5: //水曜日 str = Wed; Week = 3; break; case 6: //木曜日 str = Thurs; Week = 4; break; default: break; } } void MonthFunc() // 日がかわった時(Dayが+1した時)の月(Month)を求める関数 { if(Month == 2) //2月の場合 { //うるう年の場合 if(((Year % 4 == 0) && (Year % 100 != 0)) || //100で割り切れないで4で割れる西暦年はうるう年である。 (Year % 900 == 200) || //但し、900で割った時あまりが200または、600の西暦年も (Year % 900 == 600)) //うるう年である。(改定ユリウス暦) { if(Day >= 30) { Day = 1; Month++; } } else //うるう年でない場合 { if(Day >= 29) { Day = 1; Month++; } } } else if(Month == 12) //12月の場合 { if(Day >= 32) { Day = 1; Month = 1; Year++; } } else if( (Month == 4) || (Month == 6) || //4、6、9、11月の場合 (Month == 9) || (Month == 11) ) { if(Day >= 31) { Day = 1; Month++; } } else //2、4、6、9、11、12月以外の月 { if(Day >= 32) { Day = 1; Month++; } } } void YearFunc() // 日がかわった時(Year年の累計日数Day_This_Yearが+1した時)の年(Year)を求める関数 //うるう年の場合 if(((Year % 4 == 0) && (Year % 100 != 0)) || //100で割り切れないで4で割れる西暦年はうるう年である。 (Year % 900 == 200) || //但し、900で割った時あまりが200または、600の西暦年も (Year % 900 == 600)) //うるう年である。(改定ユリウス暦) { if(Day_This_Year >= 367) //Year年の累計日数が367日を超えた場合 { Day = 1; Year++; } } else //うるう年以外 { if(Day_This_Year >= 366) //Year年の累計日数が366日を超えた場合 { Day = 1; Year++; } } } void TimeCode() //タイムコードのパルス(パルス幅)を決める関数 { unsigned long int i; unsigned long int Temp1,Temp2,Temp3; unsigned long int Temp16,tempYear; //(1) 全タイムコードパルスの立ち上がり信号(1sec毎にOut=1) for(i = 0; i < 60; i++) if(Count_100msec == i*10)Out = 1; //(2) マーカー(M)信号OFFタイミング制御 パルス幅200msec if(Count_100msec == 2)Out = 0; //先頭マーカー(M)off //(3) ポジションマーカ(P0〜P5)信号OFFタイミング制御 パルス幅200msec for(i = 0; i < 6; i++) { if(Count_100msec == (i * 100 + 92) )Out = 0; //ポジションマーカーP0~P5 off } //(4) 0〜10sec: 分データ信号出力タイミング制御 Temp2 = (unsigned long int)Min / 10; //10進2桁目(BCD) :3ビット Temp1 = (unsigned long int)Min % 10; //10進1桁目(BCD) :4ビット Temp16 = (Temp2 << 5) + Temp1; //16ビットの送信順文字列作成 Temp16 = Temp16 & 0b1111111111101111; //第4ビットに0をセット Temp16 = Temp16 << 8; //MSBに先頭データビットを移動 //パリティ計算(偶数) PAm =bit_test (Temp2,2)^bit_test(Temp2,1)^bit_test(Temp2,0) ^bit_test(Temp1,3)^bit_test(Temp1,2)^bit_test(Temp1,1)^bit_test(Temp1,0); for(i = 1; i < 9; i++) //MSBから8bit送出 { if( (Count_100msec == (10*i + 5)) && ((0x8000 & Temp16) != 0) )Out = 0;//1の場合 15〜85 if( (Count_100msec == (10*i + 8)) && ((0x8000 & Temp16) == 0) )Out = 0;//0の場合 18〜88 Temp16 = (Temp16 << 1); } //(5) 10〜20sec: 時間データ信号出力タイミング制御 Temp2 = (unsigned long int)H /10; //10進2桁目(BCD) :2ビット Temp1 = (unsigned long int)H % 10; //10進1桁目(BCD) :4ビット Temp16 = (Temp2 << 5) + Temp1; //16ビットの送信順文字列作成 Temp16 = Temp16 & 0b1111111001101111; //第4位と第7,8位に0をセット Temp16 = (Temp16 << 7); //MSBに先頭データビットを移動 //パリティ計算(偶数) PAh = bit_test(Temp2,1)^bit_test(Temp2,0) ^bit_test(Temp1,3)^bit_test(Temp1,2)^bit_test(Temp1,1)^bit_test(Temp1,0); for(i = 0; i < 9; i++) //MSBから9ビット送出 { if( (Count_100msec == (10*i + 105)) && ((0x8000 & Temp16) != 0) )Out = 0; //1の場合 if( (Count_100msec == (10*i + 108)) && ((0x8000 & Temp16) == 0) )Out = 0; //0の場合 Temp16 = (Temp16 << 1); } //(6) 20〜30sec: 日データ信号出力タイミング制御(1) Temp3 = (unsigned long int)Day_This_Year / 100; //10進3桁目(BCD) :2ビット Temp2 = ((unsigned long int)Day_This_Year % 100) / 10; //10進2桁目(BCD) 4:ビット Temp1 = ((unsigned long int)Day_This_Year % 100) % 10; //10進1桁目(BCD) 4:ビット Temp16 = (Temp3 << 5) + Temp2; //16ビットの送信順文字列作成 Temp16 = Temp16 & 0b1111111001101111; //第4位と第7,8位に0をセット Temp16 = (Temp16 << 7); //MSBに先頭データビットを移動 for(i = 0; i < 9; i++) //MSBから9ビット送出 { if( (Count_100msec == (10*i + 205)) && ((0x8000 & Temp16) != 0) )Out = 0; //1の場合 if( (Count_100msec == (10*i + 208)) && ((0x8000 & Temp16) == 0) )Out = 0; //0の場合 Temp16 = (Temp16 << 1); } //(7) 30〜40sec: 日データ信号出力タイミング制御(2) Temp16 = (Temp1 << 5) + (PAh << 2) + (PAm << 1); Temp16 = Temp16 & 0b1111111111100111; //第3位と4位に0をセット Temp16 = (Temp16 << 7);//MSBに先頭データビットを移動 for(i = 0; i < 9; i++)//MSBから9ビット送出 { if( (Count_100msec == (10*i + 305)) && ((0x8000 & Temp16) != 0) )Out = 0; //1の場合 if( (Count_100msec == (10*i + 308)) && ((0x8000 & Temp16) == 0) )Out = 0; //0の場合 Temp16 = (Temp16 << 1); } //(8) 40〜50sec: 西暦年信号(西暦下2桁) TempYear = Year % 100; //西暦は下2桁のみ送信 Temp2 = TempYear / 10; //10進2桁目 :4ビット Temp1 = TempYear % 10; //10進1桁目 :4ビット Temp16 = (Temp2 << 4) + Temp1; //16ビットの送信順文字列作成 (予備ビット=0) Temp16 = (Temp16 << 7); //MSBに先頭データビットを移動 for(i = 0; i < 9; i++) { if( (Count_100msec == (10*i + 405)) && ((0x8000 & Temp16) != 0) )Out = 0; //1の場合 if( (Count_100msec == (10*i + 408)) && ((0x8000 & Temp16) == 0) )Out = 0; //0の場合 Temp16 = (Temp16 << 1); } //(9) 50〜60sec: 曜日、うるう年、予備信号制御 Temp2 = (unsigned long int)Week; //曜日 10進1桁 :3ビット //0:日曜日 1:月曜日 2:火曜日 3:水曜日 4:木曜日 5:金曜日 6:土曜日 Temp1 = 0x00; //うるう秒、予備 :6ビット Temp16 = Temp16 = (Temp2 << 6) + (Temp1 << 4); //16ビットの送信順文字列作成 Temp16 = Temp16 & 0b1111111111110000; //第0〜3位に0をセット Temp16 = (Temp16 << 7); //MSBに先頭データビットを移動 for(i = 0; i < 9; i++) { if( (Count_100msec == (10*i + 505)) && ((0x8000 & Temp16) != 0) )Out = 0; //1の場合 if( (Count_100msec == (10*i + 508)) && ((0x8000 & Temp16) == 0) )Out = 0; //0の場合 Temp16 = (Temp16 << 1); } if(Out == 1)output_high(PIN_E2); // タイムコード出力 : ”1" = High if(Out == 0)output_low(PIN_E2); // タイムコード出力 : ”0” = Low } void time_output() // タイムコード出力モード(100msec毎) { TimeCode(); //タイムコードを出力 Sec = Count_100msec / 10; Count_100msec++; if(Count_100msec >= 600) { Count_100msec = 0; Min++; if(Min >= 60) { Min = 0; H++; if(H >= 24) { H = 0; Day++; WeekFunc(); MonthFunc(); YearFunc(); } } } } void sw_check() //各スイッチ検出、モード決定関数 { //モードセットスイッチ検出------------------------------------------------------- if(input(PIN_A2) == 0)swCount_Mode++; //RA2のモードスイッチが押されていた場合 else swCount_Mode = 0; if(swCount_Mode == 4) //25msec毎に4回スイッチONが連続検出された場合 { if(OutputMode == 1) //タイマコード出力モード { OutputMode = 0; //タイムコード出力モードの場合 → 時刻設定モード SelectMode = 0; //西暦年設定モードにセット } else OutputMode = 1; //時刻設定モードの場合 → タイムコード出力モードにセット } if(swCount_Mode >= 5)swCount_Mode = 5; //スイッチが押されつづけられた場合は //セレクトスイッチ検出------------------------------------------------------- if((input(PIN_A3) == 0) && (OutputMode == 0))swCount_Select++; //RA3のセレクトスイッチが押されていた場合 else swCount_Select = 0; if(swCount_Select == 4) //25msec毎に4回スイッチONが連続検出された場合 { if(SelectMode == 0)SelectMode = 1; //西暦年設定モードの場合 → 月設定モード else if(SelectMode == 1)SelectMode = 2; //月設定モードの場合 → 日設定モード else if(SelectMode == 2)SelectMode = 3; //日設定モードの場合 → 時設定モード else if(SelectMode == 3)SelectMode = 4; //時設定モードの場合 → 分設定モード else if(SelectMode == 4)SelectMode = 5; //分設定モードの場合 → 秒設定モード else SelectMode = 0; //秒設定モードの場合 → 西暦年設定モード } if(swCount_Select >= 5)swCount_Select = 5; //スイッチが押されつづけられた場合は //アップスイッチ検出--------------------------------------------------------------- if((input(PIN_A5) == 0) && (OutputMode == 0))swCount_Up++; //RA5のアップスイッチが押されていた場合 else swCount_Up = 0; if(swCount_Up == 4) //25msec毎に4回スイッチONが連続検出された場合 { if(SelectMode == 0)Year++; //西暦年設定モードの場合 else if(SelectMode == 1) //月設定モードの場合 { Month++; if(Month >= 12)Month = 12; } else if(SelectMode == 2) //日設定モードの場合 { Day++; if( (Month == 4) || (Month == 6) || //4、6、9、11月の場合 (Month == 9) || (Month == 11) ) { if(Day >= 31)Day = 30; } else if(Month == 2) //2月の場合 { //うるう年の場合 if(((Year % 4 == 0) && (Year % 100 != 0)) || //100で割り切れないで4で割れる西暦年はうるう年である。 (Year % 900 == 200) || //但し、900で割った時あまりが200または、600の西暦年も (year % 900 == 600)) //うるう年である。(改定ユリウス暦) { if(Day >=30)Day = 29; } else //うるう年以外 { if(Day >=29)Day = 28; } } else //1月、3月、5月、7月、8月、10月、12月の場合 { if(Day >= 32)Day = 31; } } else if(SelectMode == 3) //時設定の場合 { H++; if(H >= 24)H = 23; } else if(SelectMode == 4) //分設定の場合 { Min++; if(Min >= 60)Min = 59; } else //秒設定の場合 { Sec++; Count_100msec = Count_100msec + 10; Count_25msec = 0; if(Sec >= 60) { Sec = 59; Count_100msec = 590; } } WeekFunc(); } if(swCount_Up >= 5)swCount_Up = 5; //スイッチが押されつづけられた場合は //ダウンスイッチ検出--------------------------------------------------------------- if((input(PIN_E0) == 0) && (OutputMode == 0))swCount_Down++; //RA3のセレクトスイッチが押されていた場合 else swCount_Down = 0; if(swCount_Down == 4) //25msec毎に4回スイッチONが連続検出された場合 { if(SelectMode == 0) //西暦年設定モードの場合 { Year--; if(Year <= 1999)Year = 2000; } else if(SelectMode == 1) //月設定モードの場合 { Month--; if(Month <= 0) Month = 1; } else if(SelectMode == 2) //日設定モードの場合 { Day--; if(Day <= 0) Day = 1; } else if(SelectMode == 3) //時設定モードの場合 { H--; if(H <= -1)H = 0; } else if(SelectMode == 4) //分設定モードの場合 { Min--; if(Min <= -1)Min = 0; } else //秒設定モードの場合 { Sec--; Count_100msec = Count_100msec - 10; Count_25msec = 0; if(Sec <= -1) { Sec = 0; Count_100msec =0; } } WeekFunc(); } if(swCount_Down >= 5)swCount_Down = 5; //スイッチが押されつづけられた場合は } #int_timer0 //タイマ1割込み(25msec毎に割込み発生) interval() { set_timer0(49911); // 0.05μsec × 4 × 8 × 15625 = 10000μsec = 25msec (at システムクロック20MHz) // 256×256 - 15625 = 49911 sw_check(); //スイッチ入力をチェック Count_25msec++; if(Count_25msec >= 4) //100msec毎 { Count_25msec = 0; if(OutputMode == 1) time_output(); // タイムコード出力モードであれば100msec毎 // 液晶表示 lcd_clear(); printf(lcd_data,"%ld.%ld.%ld %s ",Year,Month,Day,str); // lcd_cmd(0xC0); // 2行目の先頭へ if(OutputMode == 1)sprintf(str_Mode," "); //タイムコード出力モード else // 年月日時分秒の設定モード { switch(SelectMode) { case 0: //西暦年設定 sprintf(str_Mode,"(Year)"); break; case 1: //月設定 sprintf(str_Mode,"(Month)"); break; case 2: //日設定 sprintf(str_Mode,"(Day)"); break; case 3: //時設定.. sprintf(str_Mode,"(H)"); break; case 4: //分設定 sprintf(str_Mode,"(Min)"); break; case 5: //秒設定 sprintf(str_Mode,"(Sec)"); break; default: break; } } printf(lcd_data,"%ld:%ld:%ld %s",H,Min,Sec,str_Mode); // } return 0; } main(){ setup_timer_0(RTCC_INTERNAL |RTCC_DIV_8); set_timer0(49911); lcd_init(); lcd_cmd(0b00001100); // カーソル:OFF ブリンク:OFF lcd_clear(); printf(lcd_data,"TimeCode Start"); WeekFunc(); delay_ms(1000); output_low(PIN_E2); enable_interrupts(INT_TIMER0); enable_interrupts(GLOBAL); while(1) // 割込みを待つ { } return 0; } //--------------------------------------------------------------------------- //************************************** //インクルードファイル 1lcd_lib.c //このファイルは後閑哲也さんが設計されたものです //************************************** /////////////////////////////////////////////// // 液晶表示器制御ライブラリ // 内蔵関数は以下 // lcd_init() ----- 初期化 // lcd_cmd(cmd) ----- コマンド出力 // lcd_data(chr) ----- 1文字表示出力 // lcd_clear() ----- 全消去 //////// データ出力サブ関数 void lcd_out(int code, int flag) { output_x((code & 0xF0) | (input_x() & 0x0F)); if (flag == 0) output_high(rs); //表示データの場合 else output_low(rs); //コマンドデータの場合 delay_cycles(4); //NOP 1 output_high(stb); //strobe out delay_cycles(8); //NOP 2 output_low(stb); //reset strobe } //////// 1文字表示関数 void lcd_data(int asci) { lcd_out(asci, 0); //上位4ビット出力 lcd_out(asci<<4, 0); //下位4ビット出力 delay_us(50); //50μsec待ち } /////// コマンド出力関数 void lcd_cmd(int cmd) { lcd_out(cmd, 1); //上位4ビット出力 lcd_out(cmd<<4, 1); //下位4ビット出力 delay_ms(2); //2msec待ち } /////// 全消去関数 void lcd_clear() { lcd_cmd(0x01); //初期化コマンド出力 delay_ms(15); //15msec待ち } /////// 初期化関数 void lcd_init() { set_tris_x(mode); //モードセット delay_ms(15); lcd_out(0x30, 1); //8bit mode set delay_ms(5); lcd_out(0x30, 1); //8bit mode set delay_ms(1); lcd_out(0x30, 1); //8bit mode set delay_ms(1); lcd_out(0x20, 1); //4bit mode set delay_ms(1); lcd_cmd(0x2E); //DL=0 4bit mode lcd_cmd(0x08); //display off C=D=B=0 lcd_cmd(0x0D); //display on C=D=1 B=0 lcd_cmd(0x06); //entry I/D=1 S=0 lcd_cmd(0x02); //cursor home }
<動作結果>
(1) タイムコード生成
電波時計 Ver.2 キット(製造元:(有)トライステート 販売元:秋月電子通商)のタイムコード解読・表示基板を接続して
下記の動作を確認しました。
@ 電源投入直後(約7秒) 電波時計Ver.2キットがマーク(M)信号を検出しようとしている状態の写真 |
A電源投入から約2分後 マーク信号(M)を2回検出して、タイムコードの解析を開始した直後の写真 | B 電源投入から約5分後、タイムコードを解析して、時刻情報”西暦 ’07年11月3日 土曜日 0時5分3秒”を表示した直後の写真 | ||
(2) 生成する時刻(年月日時分秒)の設定
2045年8月15日を設定した時の写真を示します
設定は以下の操作となります。
@ セットボタンを押す : タイムコード出力モードから設定モードになる。設定モード中はタイムコードは出力されない
A セレクトボタンを押す : 設定変更対象が
年(Year) → 月(Month) → 日(Day) → 時(Time) →分(Min) →秒(Sec)
→年(Year) →月(Month) …… を繰り返す
B アップボタンまたはダウンボタンをおして 設定数値を1づつ増減して変更する。
C セットボタンを押す : 設定モードからタイムコード出力モードに変わる。
年設定 | 月設定 | 日設定 | ||
電波時計
★ 時刻符号(タイムコード)解読
PICでタイムコードを解読した例を紹介します。尚、タイムコード送信側のPIC4550のプログラムは上記のプログラム
で動作しています。
<試作品仕様>
・ JJYと同仕様のタイムコードを解読し 秒分時日月年曜日を液晶に表示する。
・ 受信している信号のパルス幅及び意味( ’0’、’1’、マーカー信号、ポジションマーカー信号)を液晶に表示する。
・ 直近(0〜15秒前)の受信パルスを液晶に表示する。
・ 解読の条件は以下とする。
@ 3個の連続マーカ信号検出
A 直近180秒の信号に ’0’、’1’、マーカー信号、ポジションマーカー信号以外の信号がないこと
B 直近180秒の信号において3フレームの分及び時のパリティチェックをすること
C 0〜60秒前、60〜120秒前、120〜180秒前の各フレーム内の分が1秒づつづれていること
。
<試作品回路図>(→回路図のPDFファイル)
dsPIC30F2012を使った例を紹介します。
<試作品外観>下記の写真には上記回路図にはない、また本テーマと関係のない部品が多々写っています。
<プログラム例> <dsPIC C30編> ///************************************************************/ //* 電波時計 //* JJY 時刻符号(タイムコード)解読 //* dsPIC30F2012 //************************************************************/ // MPLAB プロジェクトへの追加ファイル // Linker Scriptフォルダ p30f2012.gld // Library Filesフォルダ lib30F2012-coff.a #include "p30f2012.h" #include <stdio.h> #include <InCap.h> #include <timer.h> #include "1lcd_lib_C30.h" int Ver = 1; char Buf1[21]; char Decode_Mode = 0; //文字列のバッファー用レジスタ unsigned int FirstEdge_Rise,SecondEdge_Rise,FirstEdge_Fall,dumy, TimeCount_10msec = 0,TimeCount_sec = 0, n_TimeCode =0,i_TimeCode=0; float T0,T1; int Sec,Min,H,Week,Day,Month,Year,Day_This_Year; char data[180]; char Check[12]; char NewPulse = 0x00; char* str; char Sun[] = "Sun"; char Mon[] = "Mon"; char Thu[] = "Thu"; char Wed[] = "Wed"; char Thr[] = "Thr"; char Fri[] = "Fri"; char Sat[] = "Sat"; void delay_ms(unsigned int); void LCD(); void Month_DayFunc(); void MonthFunc(); void _ISR _IC1Interrupt(void); void _ISR _IC2Interrupt(void); void _ISR _T1Interrupt(void); void decode(); void Receive(); _FOSC(CSW_FSCM_OFF & // クロック切り替えなし、フェースセイフクロックモニタなし XT_PLL4 //外部発振子:10MHz、PLL:4倍 → システムクロック周波数=10×4=40MHz //4,8,16倍が選択可 ); _FWDT(WDT_OFF); _FBORPOR(PBOR_ON & //ブラウンアウトリセット機能:ON BORV_42 & //ブラウンアウト電圧:4.2V PWRT_64 & //パワーオンリセットタイマ64msec MCLR_EN //MCLR機能:ON ); _FGS(CODE_PROT_OFF); //コードプロテクト:OFF void delay_ms(unsigned int N) //ウェイト関数 { __delay32(Clock/4000*N); } void Month_DayFunc() //1月1日からの累計日数から月と日を求める関数 { int Day_Feb; if((Year % 4 == 0) && ((Year % 100) != 0) )Day_Feb = 29;//うるう年の場合 else Day_Feb = 28; if(Day_This_Year <= 31) //1月 { Month = 1; Day = Day_This_Year; } else if(Day_This_Year <= (31 + Day_Feb))//2月 { Month = 2; Day = Day_This_Year -31; } else if(Day_This_Year <= (62+Day_Feb)) //3月 { Month = 3; Day = Day_This_Year -(31+Day_Feb); } else if(Day_This_Year <= (92+Day_Feb)) //4月 { Month = 4; Day = Day_This_Year -(62+Day_Feb); } else if(Day_This_Year <= (123+Day_Feb)) //5月 { Month = 5; Day = Day_This_Year -(92+Day_Feb); } else if(Day_This_Year <= (153+Day_Feb)) //6月 { Month =6; Day = Day_This_Year -(123+Day_Feb); } else if(Day_This_Year <= (184+Day_Feb)) //7月 { Month =7; Day = Day_This_Year -(153+Day_Feb); } else if(Day_This_Year <= (215+Day_Feb)) //8月 { Month =8; Day = Day_This_Year -(184+Day_Feb); } else if(Day_This_Year <= (245+Day_Feb)) //9月 { Month =9; Day = Day_This_Year -(215+Day_Feb); } else if(Day_This_Year <= (276+Day_Feb)) //10月 { Month =10; Day = Day_This_Year -(245+Day_Feb); } else if(Day_This_Year <= (306+Day_Feb)) //11月 { Month =11; Day = Day_This_Year -(276+Day_Feb); } else //12月 { Month = 12; Day = Day_This_Year -(306+Day_Feb); } } void MonthFunc() // 日がかわった時(Dayが+1した時)の月(Month)を求める関数 { if(Month == 2) //2月の場合 { if((Year % 4 == 0) && ((Year % 100) != 0)) //うるう年の場合 { if(Day >= 30) { Day = 1; Month++; } } else //うるう年でない場合 { if(Day >= 29) { Day = 1; Month++; } } } else if(Month == 12) //12月の場合 { if(Day >= 32) { Day = 1; Month = 1; Year++; } } else if( (Month == 4) || (Month == 6) || //4、6、9、11月の場合 (Month == 9) || (Month == 11) ) { if(Day >= 31) { Day = 1; Month++; } } else //2、4、6、9、11、12月以外の月 { if(Day >= 32) { Day = 1; Month++; } } } void decode() //タイムコード解読 { int i,x_Check,Sum,Min0,Min1,Min2; //解読開始条件 //(1) 受信データのフレーム番号を後から受信した順番にフレーム0、フレーム1、フレーム2として // フレーム0,1,2のマーカ信号3個を受信したことを確認 if((data[0] == 'M') && (data[60] == 'M') && (data[120] == 'M'))Check[0] = 0x00; else Check[0] = 0x01; //(2) フレーム0、1,2のデータがすべて有効であるかチェック x_Check = 0x00; for(i = 0; i < 180; i++) { if(data[i] == 'x')x_Check++; } if(x_Check == 0x00)Check[1] = 0x00; else Check[1] = 0x01; //(3) フレーム0,1,2の”分” と ”時”のパリティ(偶数)チェック (data[i]の第0ビット以外は0) for(i = 0; i < 3; i++) { if(data[60-1+60*i]^data[60-2+60*i]^data[60-3+60*i]^ data[60-5+60*i]^data[60-6+60*i]^data[60-7+60*i]^data[60-8+60*i] == data[60-37+60*i]) Check[3+i] = 0x00; else Check[3+i] = 0x01; if(data[60-12+60*i]^data[60-13+60*i]^ data[60-15+60*i]^data[60-16+60*i]^data[60-17+60*i]^data[60-18+60*i] == data[60-36+60*i]) Check[6+i] = 0x00; else Check[6+i] = 0x01; } //(4) フレーム0とフレーム1との”分”の差が1分であること // 及び フレーム0とフレーム2との"分”の差が2分であることのチェック Min0 =((int)((data[60-1] << 2) + (data[60-2] << 1) + data[60-3]))*10 + (int)((data[60-5] << 3) + (data[60-6] << 2) + (data[60-7] << 1) + data[60-8]) +1; Min1 =((int)((data[120-1] << 2) + (data[120-2] << 1) + data[120-3]))*10 + (int)((data[120-5] << 3) + (data[120-6] << 2) + (data[120-7] << 1) + data[120-8]) +1; Min2 =((int)((data[180-1] << 2) + (data[180-2] << 1) + data[180-3]))*10 + (int)((data[180-5] << 3) + (data[180-6] << 2) + (data[180-7] << 1) + data[180-8]) +1; if( (((Min0 - Min1) == 1) || ((Min0 - Min1) == -59) ) && (((Min0 - Min2) == 2) || ((Min0 - Min2) == -58)) )Check[9] = 0x00; else Check[9] = 0x01; Sum = 0x00; for(i = 0; i < 10; i++)Sum = Sum + Check[i]; if(Sum == 0x00) //(1)~(4)の条件がすべて満足された場合に解読開始 { Decode_Mode = 1; Sec = 0; //正分(毎分0秒) ← マーク信号を検出したので //分を解読 Min =((int)((data[60-1] << 2) + (data[60-2] << 1) + data[60-3]))*10 + (int)((data[60-5] << 3) + (data[60-6] << 2) + (data[60-7] << 1) + data[60-8]) +1; //時を解読 H = ((int)((data[60-12] << 1) + data[60-13]))*10 + (int)((data[60-15] << 3) + (data[60-16] << 2) + (data[60-17] << 1) + data[60-18]); //1月1日からの累計日数を解読 Day_This_Year = ((int)((data[60-22] << 1) + data[60-23] ))*100 + ((int)((data[60-25] << 3) + (data[60-26] << 2) + (data[60-27] << 1) + data[60-28]))*10 + (int)((data[60-30] << 3) + (data[60-31] << 2) + (data[60-32] << 1) + data[60-33]); //西暦下2桁を解読 Year = ((int)((data[60-41] << 3) + (data[60-42] << 2) + (data[60-43] << 1) + data[60-44]))*10 + (int)((data[60-45] << 3) + (data[60-46] << 2) + (data[60-47] << 1) + data[60-48]); //年と累計日数から 日と月を計算 Month_DayFunc(); //→ Day, Monthを計算 //何曜日かを解読 Week = (int)((data[60-50] << 2) + (data[60-51] << 1) + data[60-52]); } } void Receive() //データ受信関数 : 受信パルスを判別 { int i; char temp; if((T1 > 150000) && (T1 < 250000)) { temp = 'P'; //パルス幅200msec → マーカ(M)またはポジションマーカ(P0-P5)検出の場合 if(data[0] == 'P')temp = 'M'; //幅200msecのパルスが連続していた場合は data[0]をマーク信号(M)と判断 } else if((T1 >450000) && (T1 < 550000))temp = 0x01; //論理”1”検出の場合 else if((T1 > 750000) && (T1 < 850000))temp = 0x00; //論理”0”検出の場合 else temp = 'x'; //パルス幅が200msec、500msec、8000msecのいずれでもない場合 for(i = 179; i > 0; i--)data[i] = data[i-1]; //一番古い受信データを破棄し、受信データ格納配列番号を繰り上げる data[0] = temp; decode(); NewPulse = 0x00; } void _ISR _IC1Interrupt(void) //立ち上がりエッジ毎に割込み発生 周期検出 { ReadCapture1(&FirstEdge_Rise); T0 = (float)(FirstEdge_Rise)*25.6; // パルスの周期 // カウントクロックの周期(1/Fosc×4) ΔT = 1/40MHz ×4×256(プリスケーラ) =25.6μsec //Foscが80MHzの場合 // カウントクロックの周期(1/Fosc×4) ΔT = 1/80MHz ×4×256(プリスケーラ) =12.8μsec // キャプチャ(16ビット)でカウントできる最大時間 = 12.8μsec×65536 = 838860.8μsec // =838.8608msec < 1000msec(タイムコードの周期) → 80MHzはNG do { ReadCapture1(&dumy); //FIFOバッファクリア → FIFOバッファが空(IC2CONbits.ICBNE=0)に }while(IC2CONbits.ICBNE); //ならないと次の割り込みはかからない TMR2 = 0; //タイマ2のカウント値リセット→0 IFS0bits.IC1IF = 0; //フラグクリア } void _ISR _IC2Interrupt(void) //立ち下がりエッジ毎に割込み発生 パルス幅検出 { ReadCapture2(&FirstEdge_Fall); T1 = (float)FirstEdge_Fall*25.6; //パルスのHigh(1)の時間 NewPulse = 0x01; do { ReadCapture2(&dumy); //FIFOバッファクリア → FIFOバッファが空(IC2CONbits.ICBNE=0)に }while(IC2CONbits.ICBNE); //ならないと次の割り込みはかからない IFS0bits.IC2IF = 0; //フラグクリア } void _ISR _T1Interrupt(void) //10msec毎の割込み発生 { IFS0bits.T1IF = 0; //IFS0レジスタの T1IF(タイマ1の割込み検出)フラグリセット TimeCount_10msec++; //10msec毎にインクリメント if(TimeCount_10msec >= 100) { Sec++; TimeCount_10msec = 0; if(Sec >= 60) { Sec = 0; Min++; if(Min >= 60) { Min = 0; H++; if(H >= 24) { H = 0; Day++; Week++; if(Week >= 7)Week =0; MonthFunc(); } } } } } void LCD() //液晶表示 { unsigned int T0x,T1x; char temp0,temp1; char pulse; char te[8]; char data_t[16]; int i; lcd_clear(); T0x = (unsigned int)(T0/1000); T1x = (unsigned int)(T1/1000); for(i = 0; i <16; i++) { if(data[i] == 0x00)data_t[i] = 0x30; else if(data[i] == 0x01)data_t[i] = 0x31; else data_t[i] = data[i]; } switch(Decode_Mode) { case 0: //マーカ信号検出中&受信データ収集中 sprintf(Buf1,"T1=%umsec '%c'",T1x,data_t[0]); //文字列としてバッファーに収納 lcd_str(Buf1); lcd_cmd(0xC0); sprintf(Buf1,"%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c", data_t[0],data_t[1],data_t[2],data_t[3],data_t[4],data_t[5],data_t[6],data_t[7],//文字列としてバッファーに収納 data_t[8],data_t[9],data_t[10],data_t[11],data_t[12],data_t[13],data_t[14],data_t[15]);//文字列としてバッファーに収納 lcd_str(Buf1); delay_ms(100); break; case 1: // タイムコード解読後 //07/11/03 Sat 'M' //15:23:12 200msec switch(Week) { case 0: str = Sun; break; //日曜日 case 1: str = Mon; break; //月曜日 case 2: str = Thu; break; //火曜日 case 3: str = Wed; break; //水曜日 case 4: str = Thr; break; //木曜日 case 5: str = Fri; break; //金曜日 case 6: str = Sat; break; //土曜日 default: break; } sprintf(Buf1,"'%d/%d/%d %s '%c'",Year,Month,Day,str,data_t[0]); lcd_str(Buf1); lcd_cmd(0xC0); //2行目の先頭へ sprintf(Buf1,"%d:%d:%d %umsec ",H,Min,Sec,T1x); //文字列としてバッファーに収納 lcd_str(Buf1); delay_ms(100); break; default: break; } } int main(void) //メイン関数 { TRISB = 0; TRISF = 0b1111111111001111; TRISD = 0xFFFF; OpenTimer1(T1_ON & //タイマ1ON T1_GATE_OFF & //ゲート制御ON T1_PS_1_8 & //プリスケーラ 1/8 T1_SYNC_EXT_OFF & //クロック同期制御OFF T1_SOURCE_INT , //クロック源:内部クロック 12499 //10msec毎に割込み → 10msec × 1000 × (40MHz/4MHz) / 8 = 12500 //PR1 = 12499 ( =12500 - 1) ); // OpenTimer2(T2_ON & T2_GATE_OFF & T2_PS_1_256 & T2_SOURCE_INT, 65000-1); //動作モード設定レジスタ IC2CONの設定 OpenCapture1(IC_IDLE_STOP & //Idle時停止 IC_TIMER2_SRC & //タイマ2で測定 IC_INT_1CAPTURE & //キャプチャー毎に割込み発生 IC_EVERY_RISE_EDGE //立ち上がりエッジ毎にキャプチャー ); OpenCapture2(IC_IDLE_STOP & //Idle時停止 IC_TIMER2_SRC & //タイマ2で測定 IC_INT_1CAPTURE & //キャプチャー毎に割込み発生 IC_EVERY_FALL_EDGE //立ちさがりエッジ毎にキャプチャー ); lcd_init(); // LCD初期化 lcd_cmd(0b00001100); // カーソル:OFF ブリンク:OFF lcd_clear(); // 全消去 sprintf(Buf1,"Cap %d",Ver); //arguementがないと遅い C30のバグ? lcd_str(Buf1); //液晶表示 delay_ms(1000); ConfigIntTimer1(T1_INT_PRIOR_5 & T1_INT_ON); //割込みレベル5 タイマ1割込みON ConfigIntCapture1(IC_INT_PRIOR_4 & IC_INT_ON); //IPC1bits.IC1IP = 4; ConfigIntCapture2(IC_INT_PRIOR_3 & IC_INT_ON); //IPC1bits.IC2IP = 3; EnableIntT1; //割込み許可 EnableIntIC1; //割込み許可 IEC0bits.IC1IE = 1; EnableIntIC2; //割込み許可 IEC0bits.IC2IE = 1; while(1) //割込みを待つ { LCD(); if(NewPulse ==0x01)Receive(); } return 0; } //******************************************************************************************** //インクルードファイル 1lcd_lib_C30.h //このファイルは後閑哲也さんが設計されたCCSコンパイラ用液晶表示ライブラリ 1lcd_lib.cをもとに、 //C30コンパイラ対応 及び分散ポート対応等で変更したものです。 //******************************************************************************************** #include "p30f2012.h" #define Clock 40000000 // 単位はHzで指定 // LCDポート設定 #define lcd_port_DB7 LATBbits.LATB7 //LCDのDB7(14番ピン)に接続されるPIC側ポート番号設定 #define lcd_port_DB6 LATBbits.LATB6 //LCDのDB6(13番ピン)に接続されるPIC側ポート番号設定 #define lcd_port_DB5 LATBbits.LATB5 //LCDのDB5(12番ピン)に接続されるPIC側ポート番号設定 #define lcd_port_DB4 LATBbits.LATB4 //LCDのDB4(11番ピン)に接続されつPIC側ポート番号設定 #define lcd_stb LATFbits.LATF4 //LCDのstb(6番ピン)に接続されるPIC側ポート番号設定 #define lcd_rs LATFbits.LATF5 //LCDのrs(4番ピン)に接続されるPIC側ポート番号設定 void lcd_out(char code, char flag); void lcd_data(char asci); void lcd_cmd(char cmd); void lcd_clear(void); void lcd_init(void); void lcd_str(char *str); //******************************************************************************************** //インクルードファイル 1lcd_lib_C30.c //このファイルは後閑哲也さんが設計されたCCSコンパイラ用液晶表示ライブラリ 1lcd_lib.cをもとに、 //C30コンパイラ対応、及び分散ポート対応等で変更を加えたものです。 //******************************************************************************************** /////////////////////////////////////////////// // 液晶表示器制御ライブラリ for C30コンパイラー // 内蔵関数は以下 // lcd_init() ----- 初期化 // lcd_cmd(cmd) ----- コマンド出力 // lcd_data(chr) ----- 1文字表示出力 // lcd_clear() ----- 全消去 // lcd_str(str*) ----- 文字列表示 ////////////////////////////////////////////// #include "1lcd_lib_C30.h" unsigned int _1usec; // 1μsec待つに必要なウェイト回数 unsigned int _50usec; //50μsec待つに必要なウェイト回数 unsigned long N_msec; // 1msec待つに必要なウェイト回数 //////// データ出力サブ関数 void lcd_out(char code, char flag) { if(code & 0b10000000)lcd_port_DB7 = 1; //LCDのDB7への出力セット else lcd_port_DB7 = 0; if(code & 0b01000000)lcd_port_DB6 = 1; //LCDのDB6への出力セット else lcd_port_DB6 = 0; if(code & 0b00100000)lcd_port_DB5 = 1; //LCDのDB5への出力セット else lcd_port_DB5 = 0; if(code & 0b00010000)lcd_port_DB4 = 1; //LCDのDB4への出力セット else lcd_port_DB4 = 0; if (flag == 0) lcd_rs = 1; // 表示データの場合 else lcd_rs = 0; // コマンドデータの場合 __delay32(_1usec); //1μsecウェイト lcd_stb = 1; // strobe(E) ON (Enable) __delay32(_1usec); // 1μsec : strobe信号の幅 lcd_stb = 0; // reset strobe } //////// 1文字表示関数 void lcd_data(char asci) { lcd_out(asci, 0); // 上位4ビット出力 lcd_out(asci<<4, 0); // 下位4ビット出力 __delay32(_50usec); //50μsecウェイト } /////// コマンド出力関数 void lcd_cmd(char cmd) { lcd_out(cmd, 1); // 上位4ビット出力 lcd_out(cmd<<4, 1); // 下位4ビット出力 if((cmd & 0x03) != 0) // clear Homeの場合 __delay32(2*N_msec); // 2msec待ち else __delay32(_50usec); //50μsecウェイト } /////// 全消去関数 void lcd_clear(void) { lcd_cmd(0x01); // 初期化コマンド出力 // __delay32(15*N_msec); //15msecウェイト } /////// 文字列出力関数 void lcd_str(char* str) { while(*str) //文字列終端の '\0'を検出するまで { lcd_data(*str); // 1文字表示 str++; //ポインタをインクリメント } } /////// 初期化関数 void lcd_init(void) { _1usec =(unsigned int)( Clock / 4000000); // 1μsecに要するウェイト回数 //__delay32(N) : Nが11以下の場合でも11回ウェイト _50usec = (unsigned int)(Clock / 4000000 * 50); //50μescに要するウェイト回数 N_msec = (unsigned long int)(Clock / 4000); // 1msecに要するウェイト回数 // = Clock / 4000000*1000 __delay32(20*N_msec); //20msecウェイト lcd_out(0x30, 1); // 8bit mode set __delay32(5*N_msec); //5msecウェイト lcd_out(0x30, 1); // 8bit mode set __delay32(N_msec); //1msecウェイト lcd_out(0x30, 1); // 8bit mode set __delay32(N_msec); //1msecウェイト lcd_out(0x20, 1); // 4bit mode set __delay32(N_msec); //1msecウェイト lcd_cmd(0x2E); // DL=0 4bit mode lcd_cmd(0x08); // display off C=D=B=0 lcd_cmd(0x0D); // display on C=D=1 B=0 lcd_cmd(0x06); // entry I/D=1 S=0 lcd_cmd(0x02); // cursor home }
<動作結果>
1.JJY仕様のタイムコードを解読中と解読直後の写真を下記に示します。
<タイムコード解読中>
・液晶の1行目の ”T1=800msec 0 ” は パルス幅800msec(周期:1sec)のパルスを受信し、パルスの意味は
論理’0’(ゼロ)である と云うことをあらわしています。
・液晶の2行目の ”000P00000100MP00” は 0〜15秒前に受信したパルスの意味をあらわしています。
@ 最上位(左端)0 : 直近の受信信号が’0’であったことを示しています
A 左端から2,3番目の0 : 1秒前、2秒前の信号が0であったことを示しています
B 左端から4番目のP : 3秒前にポジションマーカー(幅200msec)を受信したことを示しています
C 左端から5〜9番目の0: 4〜8秒前の受信信号が0であったことを示しています
D 左端から10番目の1 : 9秒前の受信信号が1であったことを示しています。
E 左端から13番目のM : 12秒前の受信信号がマーカーであったことを示しています
F 左端から14番目のP : 13秒前の受信信号がポジションマーカであったことを示しています。
<タイムコード解読完了>
・液晶の1行目の ” ’7/11/3 Sat ’0’ ” は 西暦(下二桁)7年11月3日 土曜日 を受信したことを示します。
’0’は 論理’0’を受信した直後であることを示しています。
・0:13:14 800msec は受信した時刻が 午前0時13分14秒であることを示しています。 800msecは パルス
幅800msecのパルスを受信した直後であることを示しています。 800msecはJJYタイムコードでは論理’0’と規定
されています。。
タイムコード解読中 (受信開始 18秒後) |
タイムコード解読完了 (受信開始 3分19秒後) |
|
左下の液晶がタイムコード送信側の液晶で、 右上側の液晶が受信側の液晶です |
2. 受信パルス
タイムコード解読中に各パルスを受信した時の写真を以下に示します。
ポジションマーカー (パルス幅200msec) |
||
マーカー (パルス幅200msec) (注) |
||
論理’1’ (パルス幅500msec) |
||
論理’0’ (パルス幅800msec) |
(注)パルス幅200msecのパルスを2個連続して受信した場合、後のパルスをマーカー信号と判読しています。
■ 圧電ブザーによるドレミファソラシド音 <XC32 PIC32MX795F512L>
<仕様>
・圧電ブザー(圧電サウンダー)で ドレミファソラシド ドシラソファミレドの音を PIC32MXで発する。
各音階の周波数は下記とする
音階 | 周波数(Hz) |
ド | 261.63 |
レ | 293.67 |
ミ | 329.63 |
ファ | 349.23 |
ソ | 392.00 |
ラ | 440.00 |
シ | 493.88 |
ド | 523.23 |
・ブザー音量は可変できること。
・ソフトはOC(Output Compare)のPWMモジュールを使うこと。
・圧電ブザーは、村田製作所 PKM13EPYH4000-A0 (秋月電子販売部品)とする。
<試作品回路図>(→回路図のPDFファイル)
PIC32MX795F512Lを使った例を紹介します。
<試作品外観>下記の写真には上記回路図にはない、また本テーマと関係のない部品が多々写っています
<プログラム例> #include <p32xxxx.h> #include <plib.h> // コンフィギュレーション設定 // CPU=80MHz Peri=80MHz,HS+PLL,Divider=1/2,PLL=x20,WDT=Off #pragma config FNOSC=PRIPLL, POSCMOD=HS, FPLLIDIV=DIV_2 #pragma config FPLLMUL=MUL_20, FPBDIV=DIV_1, FPLLODIV=DIV_1 #pragma config FWDTEN=OFF, ICESEL=ICS_PGx2 int Clock = 80000000; //80MHz void delay_us(unsigned int usec) //1μsec遅延関数 { int count; count = (int)(Clock/20000000)*usec; do //実測: at Clock=80000000 { //delay_us(1000)→1003μsec、 delay_us(100)→102μsec、delay_us(10)→11μsec、delay_us(1)→1.6μsec asm("NOP"); asm("NOP"); asm("NOP"); asm("NOP"); asm("NOP"); asm("NOP"); asm("NOP"); asm("NOP"); asm("NOP"); asm("NOP"); count--; }while(count != 0); } void delay_ms(unsigned int msec) //1msec遅延関数 { unsigned int i; for(i=0; i<msec; i++) delay_us(1000); } void BuzFreq(int Freq,float Duty) { int PR; //PWM周期のレジスタ値( = PR2) float PS_T2 = 16; //タイマ2のプリスケール値 PR = (int)(80000000/Freq/PS_T2); //80000000: システムクロック( PICMX32は1クロックで1命令) //例: 圧電ブザー周波数 1000Hz、プリスケール値:16 の場合 // PR = 80000000/1000/16 = 5000 OpenTimer2( T2_ON | // タイマ1 イネーブル //T1_OFF → タイマ1 ディセーブル T2_SOURCE_INT | //クロックソース:インターナル //T1_SOURCE_EXT → 外部発振器 T2_PS_1_16, //プリスケール 1/16 //1/1、1/2、1/4、1/8、1/16、1/32、1/64、1/256 PR //(例) PR = 10000 : T0[sec] = 1/80000000*16*10000 =0.002sec = 2msec //500Hz //PICMX32は1クロックで1命令 //周期 T0[sec] = 1/Fosc /プリスケーラ × PR ); OpenOC4( OC_ON | OC_TIMER_MODE16 | OC_TIMER2_SRC | OC_PWM_FAULT_PIN_DISABLE,0,0); //SRC: source //OCxの可能設定タイマ // OC1 : Timer4 Timer5 // OC2 : Timer4 Timer5 // OC3 : Timer4 Timer5 // OC4 : Timer2 Timer3 // OC5 : Timer2 Timer3 SetDCOC4PWM((int)PR*Duty); //OCxRS(旧 DC1)への書込み } void Do1(void){ BuzFreq(261.63,0.5);//ド //261.63Hz } void Re1(void) { BuzFreq(293.67,0.5); //レ //293.67Hz } void Mi1(void) { BuzFreq(329.63,0.5); //ミ //329.63Hz } void Fa1(void) { BuzFreq(349.23,0.5); //ファ //349.23Hz } void So1(void) { BuzFreq(392,0.5); //ソ //392Hz } void Ra1(void) { BuzFreq(440.00,0.7); //ラ //440.00Hz } void Si1(void) { BuzFreq(493.88,0.4); //シ //493.88Hz } void Do2(void) { BuzFreq(523.23,0.5); //ド //523.23Hz } int main(void) { int T0 = 300; SYSTEMConfigPerformance(Clock); // システム最適化 DDPCONbits.JTAGEN = 0; //I/OポートとしてRA0、RA1、RA4、RA5をつかう場合、電源投入後DDPCONレジスタのbit3を0に、設定する必要があり;ます。 TRISDbits.TRISD3 = 0; //RD3: out while(1) { Do1(); //ド delay_ms(T0); CloseTimer2(); Re1(); //レ delay_ms(T0); CloseTimer2(); Mi1(); //ミ delay_ms(T0); CloseTimer2(); Fa1(); //ファ delay_ms(T0); CloseTimer2(); So1(); //ソ delay_ms(T0); CloseTimer2(); Ra1(); //ラ delay_ms(T0); CloseTimer2(); Si1(); //シ delay_ms(T0); CloseTimer2(); Do2(); //ド delay_ms(T0); CloseTimer2(); delay_ms(2000); Do2(); //ド delay_ms(T0); // CloseTimer2(); Si1(); //シ delay_ms(T0); // CloseTimer2(); Ra1(); //ラ delay_ms(T0); // CloseTimer2(); So1(); //ソ delay_ms(T0); // CloseTimer2(); Fa1(); //ファ delay_ms(T0); // CloseTimer2(); Mi1(); //ミ delay_ms(T0); // CloseTimer2(); Re1(); //レ delay_ms(T0); // CloseTimer2(); Do1(); //ド delay_ms(T0); // CloseTimer2(); delay_ms(2000); } return 0; }
<動作結果>
圧電ブザーが 発音した ドレミファソラシド ドシラソファミレド を 録音したファイル(Sounder_DoReMi.aac)です。 PCで再生して聞いてください。。
■ 圧電スピーカによる 唱歌「ふるさと」<PIC32MX795F512L>
<仕様>
・PIC32MX795F512LのコンペアモジュールのPWM制御により、 下記のケイタイなどでつかわれている圧電スピーカをつかって唱歌を演奏する。
村田製作所 Piezoelectric Speaker VSLBP2115E1100-T1
Rated Frequency Range 200Hz to 20kHz
Sound Pressure Level 93.5dB±3.0dB
・演奏する 唱歌は「ふるさと」とし、下記楽譜の調(ヘ長調)、テンポ(80)、音符 及び休止符等に
したがって 圧電スピーカの吹鳴周波数、吹鳴時間 及び休止時間等を定め演奏のこと。
<試作品回路図>(→回路図のPDFファイル)
<試作品外観>下記の写真には上記回路図にはない、また本テーマと関係のない部品が多々写っています
<プログラム例> #include <p32xxxx.h> #include <plib.h> // コンフィギュレーション設定 // CPU=80MHz Peri=80MHz,HS+PLL,Divider=1/2,PLL=x20,WDT=Off #pragma config FNOSC=PRIPLL, POSCMOD=HS, FPLLIDIV=DIV_2 #pragma config FPLLMUL=MUL_20, FPBDIV=DIV_1, FPLLODIV=DIV_1 #pragma config FWDTEN=OFF, ICESEL=ICS_PGx2 int Clock = 80000000; //80MHz int T4; //四分音符の時間[msec] int tempo_speed = 80; //テンポ=80 void delay_us(unsigned int usec) //1μsec遅延関数 { int count; count = (int)(Clock/20000000)*usec; do //実測: at Clock=80000000 { //delay_us(1000)→1003μsec、 delay_us(100)→102μsec、delay_us(10)→11μsec、delay_us(1)→1.6μsec asm("NOP"); asm("NOP"); asm("NOP"); asm("NOP"); asm("NOP"); asm("NOP"); asm("NOP"); asm("NOP"); asm("NOP"); asm("NOP"); count--; }while(count != 0); } void delay_ms(unsigned int msec) //1msec遅延関数 { unsigned int i; for(i=0; i<msec; i++) delay_us(1000); } void BuzFreq(int Freq,float Duty) { int PR; //PWM周期のレジスタ値( = PR2) float PS_T2 = 16; //タイマ2のプリスケール値 PR = (int)(80000000/Freq/PS_T2); //80000000: システムクロック( PICMX32は1クロックで1命令) //例: 圧電ブザー周波数 1000Hz、プリスケール値:16 の場合 // PR = 80000000/1000/16 = 5000 OpenTimer2( T2_ON | // タイマ1 イネーブル //T1_OFF → タイマ1 ディセーブル T2_SOURCE_INT | //クロックソース:インターナル //T1_SOURCE_EXT → 外部発振器 T2_PS_1_16, //プリスケール 1/16 //1/1、1/2、1/4、1/8、1/16、1/32、1/64、1/256 PR //(例) PR = 10000 : T0[sec] = 1/80000000*16*10000 =0.002sec = 2msec //500Hz //PICMX32は1クロックで1命令 //周期 T0[sec] = 1/Fosc /プリスケーラ × PR ); OpenOC4( OC_ON | OC_TIMER_MODE16 | OC_TIMER2_SRC | OC_PWM_FAULT_PIN_DISABLE,0,0); //SRC: source //OCxの可能設定タイマ // OC1 : Timer4 Timer5 // OC2 : Timer4 Timer5 // OC3 : Timer4 Timer5 // OC4 : Timer2 Timer3 // OC5 : Timer2 Timer3 SetDCOC4PWM((int)PR*Duty); //OCxRS(旧 DC1)への書込み } void Do_C4(void) //第四オクターブ ド //C4 { BuzFreq(261.63,0.5);//ド //261.63Hz } void Re_D4(void) //第四オクターブ レ //D4 { BuzFreq(293.67,0.5); //レ //293.67Hz } void Mi_E4(void) //第四オクターブ ミ //E4 { BuzFreq(329.63,0.5); //ミ //329.63Hz } void Fa_F4(void) //第四オクターブ ファ //F4 { BuzFreq(349.23,0.5); //ファ //349.23Hz } void So_G4(void) //第四オクターブ ソ //G4 { BuzFreq(392,0.5); //ソ //392Hz } void La_A4(void) //第四オクターブ ラ //A4 { BuzFreq(440.00,0.7); //ラ //440.00Hz } void La_sharpA4(void) //第四オクターブ #ラ(嬰イ) //A#4 { BuzFreq(466.16,0.7); //ラ //466.16Hz } void Si_B4(void) //第四オクターブ シ //B4 { BuzFreq(493.88,0.4); //シ //493.88Hz } void Do_C5(void) //第五オクターブ ド //C5 { BuzFreq(523.23,0.5); //ド //523.23Hz } void Re_D5(void) //第五オクターブ レ { BuzFreq(587.34,0.5); //レ //587.34Hz } void noSound(void) { CloseTimer2(); delay_ms(50); } int main(void) { int T0 = 300; SYSTEMConfigPerformance(Clock); // システム最適化 DDPCONbits.JTAGEN = 0; //I/OポートとしてRA0、RA1、RA4、RA5をつかう場合、電源投入後DDPCONレジスタのbit3を0に、設定する必要があり;ます。 TRISDbits.TRISD3 = 0; //RD3: out T4 = 60 * 1000 / 80; //四分音符の時間(長さ) T4 = 750 [msec] while(1) { // へ長調 //固定ド唱法 //第1行: うさぎ追いし かの山 ----------------------------------------------------------- //-----第一小節 Fa_F4(); //ファ delay_ms(T4); //四分音符長さ noSound(); Fa_F4(); //ファ delay_ms(T4); //四分音符長さ noSound(); Fa_F4(); //ファ delay_ms(T4); //四分音符長さ noSound(); //------第二小節 So_G4(); //ソ delay_ms(T4*1.5);//付点付四分音符長さ noSound(); La_A4(); //ラ delay_ms(T4/2); //八分音符長さ noSound(); So_G4(); //ソ delay_ms(T4); //四分音符長さ noSound(); //-------第三小節 La_A4(); //ラ delay_ms(T4); //四分音符長さ noSound(); La_A4(); //ラ delay_ms(T4); //四分音符長さ noSound(); La_sharpA4(); //シ (#ラ) delay_ms(T4); //四分音符長さ noSound(); //--------第四小節 Do_C5(); //ド delay_ms(T4*2); //二分音符長さ noSound(); delay_ms(T4); //四分休符 //第2行 こぶな釣りし かの川 --------------------------------------------------------- //--------第一小節 La_sharpA4(); //#ラ delay_ms(T4); noSound(); Do_C5(); //ド delay_ms(T4); //四分音符長さ noSound(); Re_D5(); //レ delay_ms(T4); //四分音符長さ noSound(); //---------第二小節 La_A4(); //ラ delay_ms(T4*1.5);//付点付四分音符長さ noSound(); La_sharpA4(); //シ (#ラ) delay_ms(T4/2); //八分音符長さ noSound(); La_A4(); //ラ delay_ms(T4);//付点付四分音符長さ noSound(); //----------第三小節 So_G4(); //ソ delay_ms(T4);//付点付四分音符長さ noSound(); So_G4(); //ソ delay_ms(T4);//付点付四分音符長さ noSound(); Mi_E4(); //第四オクターブ ミ //E4 delay_ms(T4);//付点付四分音符長さ noSound(); //-----------第四小節 Fa_F4(); //ファ delay_ms(T4*2); //二分音符長さ noSound(); delay_ms(T4); //四分休符 //第3行 夢は今も めぐりて //-----------第一小節 So_G4(); //ソ delay_ms(T4/2);//八分音符長さ noSound(); Fa_F4(); //ファ delay_ms(T4/2); //八分音符長さ noSound(); So_G4(); //ソ delay_ms(T4);//四分音符長さ noSound(); Do_C4(); //ド delay_ms(T4);//四分音符長さ noSound(); //------------第二小節 Fa_F4(); //ファ delay_ms(T4/2); //八分音符長さ noSound(); So_G4(); //ソ delay_ms(T4/2);//八分音符長さ noSound(); La_A4(); //ラ delay_ms(T4);//四分音符長さ noSound(); La_A4(); //ラ delay_ms(T4);//四分音符長さ noSound(); //------------第三小節 La_sharpA4(); //シ (#ラ) delay_ms(T4/2); // 八分音符長さ noSound(); La_A4(); //ラ delay_ms(T4/2);//八分音符長さ noSound(); La_sharpA4(); //シ (#ラ) delay_ms(T4*1.5); //付点付四分音符長さ noSound(); Re_D5(); //レ delay_ms(T4/2); //八分音符長さ noSound(); //-----------第四小節 Do_C5(); //ド delay_ms(T4/2); //二分音符長さ noSound(); La_sharpA4(); //シ (#ラ) delay_ms(T4/2); //八分音符長さ noSound(); La_A4(); //ラ delay_ms(T4);//四分音符長さ noSound(); delay_ms(T4); //四分休符 //第4行 忘れがたき 故郷(ふるさと) //---------第一小節 Do_C5(); //ド delay_ms(T4); //四分音符長さ noSound(); Do_C5(); //ド delay_ms(T4); //四分音符長さ noSound(); Do_C5(); //ド delay_ms(T4); //二分音符長さ noSound(); //----------第二小節 Fa_F4(); //ファ delay_ms(T4*1.5); //付点付四分音符長さ noSound(); So_G4(); //ソ delay_ms(T4/2);//八分音符長さ noSound(); La_A4(); //ラ delay_ms(T4);//四分音符長さ noSound(); //----------第三小節 La_sharpA4(); //シ (#ラ) delay_ms(T4); //四分音符長さ noSound(); La_sharpA4(); //シ (#ラ) delay_ms(T4); //四分音符長さ noSound(); So_G4(); //ソ delay_ms(T4);//四分音符長さ noSound(); //-----------第四小節 Fa_F4(); //ファ delay_ms(T4*2); //二分音符長さ noSound(); delay_ms(T4); //四分休符 ///-------------------------------------------------------------------------------- delay_ms(1000); } return 0; }
<動作結果>
圧電スピーカによる PIC32MX795F512LのPWM制御による 唱歌「ふるさと」を 録音したファイル(*.aac)です。 PCで再生して聞いてください。。
■ 圧電スピーカによる 唱歌「ふるさと」<PIC32MZ2048ECH100>
<仕様>
・ PIC32MZ 及び ハーモニーをつかうこと
・PIC32MZ2048ECH100のOC5(Output Compare)モジュールのPWM制御により、 下記のケイタイなどでつかわれている圧電スピーカをつかって唱歌を演奏する。
村田製作所 Piezoelectric Speaker VSLBP2115E1100-T1
Rated Frequency Range 200Hz to 20kHz
Sound Pressure Level 93.5dB±3.0dB
・演奏する 唱歌は「ふるさと」とし、下記楽譜の調(ヘ長調)、テンポ(80)、音符 及び休止符等に
したがって 圧電スピーカの吹鳴周波数、吹鳴時間 及び休止時間等を定め演奏のこと。
・ 開発環境: ver. 1.03 Harmony, ver. 1.34 XC32, ver. 2.30 MPLABX , revison.
5 PIC32MZ2048ECH100
<試作品回路図>(→回路図のPDFファイル)
<試作品外観>下記の写真には上記回路図にはない、また本テーマと関係のない部品が多々写っています
<プログラム例> //以下、main.c //------------------------------------------------------------------------------------------ /******************************************************************************* MPLAB Harmony Project Main Source File Company: Microchip Technology Inc. File Name: main.c Summary: This file contains the "main" function for an MPLAB Harmony project. Description: This file contains the "main" function for an MPLAB Harmony project. The "main" function calls the "SYS_Initialize" function to initialize the state machines of all MPLAB Harmony modules in the system and it calls the "SYS_Tasks" function from within a system-wide "super" loop to maintain their correct operation. These two functions are implemented in configuration-specific files (usually "system_init.c" and "system_tasks.c") in a configuration-specific folder under the "src/system_config" folder within this project's top-level folder. An MPLAB Harmony project may have more than one configuration, each contained within it's own folder under the "system_config" folder. *******************************************************************************/ // DOM-IGNORE-BEGIN /******************************************************************************* Copyright (c) 2013-2014 released Microchip Technology Inc. All rights reserved. //Microchip licenses to you the right to use, modify, copy and distribute Software only when embedded on a Microchip microcontroller or digital signal controller that is integrated into your product or third party product (pursuant to the sublicense terms in the accompanying license agreement). You should refer to the license agreement accompanying this Software for additional information regarding your rights and obligations. SOFTWARE AND DOCUMENTATION ARE PROVIDED "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION, ANY WARRANTY OF MERCHANTABILITY, TITLE, NON-INFRINGEMENT AND FITNESS FOR A PARTICULAR PURPOSE. IN NO EVENT SHALL MICROCHIP OR ITS LICENSORS BE LIABLE OR OBLIGATED UNDER CONTRACT, NEGLIGENCE, STRICT LIABILITY, CONTRIBUTION, BREACH OF WARRANTY, OR OTHER LEGAL EQUITABLE THEORY ANY DIRECT OR INDIRECT DAMAGES OR EXPENSES INCLUDING BUT NOT LIMITED TO ANY INCIDENTAL, SPECIAL, INDIRECT, PUNITIVE OR CONSEQUENTIAL DAMAGES, LOST PROFITS OR LOST DATA, COST OF PROCUREMENT OF SUBSTITUTE GOODS, TECHNOLOGY, SERVICES, OR ANY CLAIMS BY THIRD PARTIES (INCLUDING BUT NOT LIMITED TO ANY DEFENSE THEREOF), OR OTHER SIMILAR COSTS. *******************************************************************************/ // DOM-IGNORE-END // ***************************************************************************** // ***************************************************************************** // Section: Included Files // ***************************************************************************** // ***************************************************************************** #include <stddef.h> // Defines NULL #include <stdbool.h> // Defines true #include <stdlib.h> // Defines EXIT_FAILURE #include "system/common/sys_module.h" // SYS function prototypes // ***************************************************************************** // ***************************************************************************** // Section: Main Entry Point // ***************************************************************************** // ***************************************************************************** int main ( void ) { /* Initialize all MPLAB Harmony modules, including application(s). */ SYS_Initialize ( NULL ); while ( true ) { /* Maintain state machines of all polled MPLAB Harmony modules. */ SYS_Tasks ( ); } /* Execution should not come here during normal operation */ return ( EXIT_FAILURE ); } /******************************************************************************* End of File */ //以下、app.c //---------------------------------------------------------------------------------------- /******************************************************************************* MPLAB Harmony Application Source File Company: Microchip Technology Inc. File Name: app.c Summary: This file contains the source code for the MPLAB Harmony application. Description: This file contains the source code for the MPLAB Harmony application. It implements the logic of the application's state machine and it may call API routines of other MPLAB Harmony modules in the system, such as drivers, system services, and middleware. However, it does not call any of the system interfaces (such as the "Initialize" and "Tasks" functions) of any of the modules in the system or make any assumptions about when those functions are called. That is the responsibility of the configuration-specific system files. *******************************************************************************/ // DOM-IGNORE-BEGIN /******************************************************************************* Copyright (c) 2013-2014 released Microchip Technology Inc. All rights reserved. Microchip licenses to you the right to use, modify, copy and distribute Software only when embedded on a Microchip microcontroller or digital signal controller that is integrated into your product or third party product (pursuant to the sublicense terms in the accompanying license agreement). You should refer to the license agreement accompanying this Software for additional information regarding your rights and obligations. SOFTWARE AND DOCUMENTATION ARE PROVIDED "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION, ANY WARRANTY OF MERCHANTABILITY, TITLE, NON-INFRINGEMENT AND FITNESS FOR A PARTICULAR PURPOSE. IN NO EVENT SHALL MICROCHIP OR ITS LICENSORS BE LIABLE OR OBLIGATED UNDER CONTRACT, NEGLIGENCE, STRICT LIABILITY, CONTRIBUTION, BREACH OF WARRANTY, OR OTHER LEGAL EQUITABLE THEORY ANY DIRECT OR INDIRECT DAMAGES OR EXPENSES INCLUDING BUT NOT LIMITED TO ANY INCIDENTAL, SPECIAL, INDIRECT, PUNITIVE OR CONSEQUENTIAL DAMAGES, LOST PROFITS OR LOST DATA, COST OF PROCUREMENT OF SUBSTITUTE GOODS, TECHNOLOGY, SERVICES, OR ANY CLAIMS BY THIRD PARTIES (INCLUDING BUT NOT LIMITED TO ANY DEFENSE THEREOF), OR OTHER SIMILAR COSTS. *******************************************************************************/ // DOM-IGNORE-END // ***************************************************************************** // ***************************************************************************** // Section: Included Files // ***************************************************************************** // ***************************************************************************** #include "app.h" #include "peripheral/oc/plib_oc.h" //これがないと OC_ID_5がコンパイルエラー int delay_Clock = 200000000; //200MHz int T4; //四分音符の時間[msec] int tempo_speed = 80; //テンポ=80 void delay_us(volatile unsigned int usec) //1μsec遅延 { volatile int count; count = (int)(delay_Clock/20000000)*usec; do //実測 at 200MH (Clock=200000000) { //delay_us(1000):1000.4μsec delay_us(100):100.6μsec delay_us(10):10.5μsec delay_us(1):1.5μsec asm("NOP"); asm("NOP"); asm("NOP"); asm("NOP"); asm("NOP");asm("NOP"); asm("NOP"); asm("NOP"); asm("NOP"); asm("NOP"); asm("NOP"); asm("NOP"); count--; }while(count != 0); } void delay_ms(volatile unsigned int msec) //1msec遅延 { volatile unsigned int i; //実測:at200MH (Clock=200000000)//delay_ms(1): 1.0006msec delay_ms(100):100.04msec for(i=0; i<msec; i++) delay_us(1000); } void BuzFreq(volatile int Freq, volatile float Duty) //PWM周波数、 デューティの設定関数 { volatile int myPR; //PWM周期のレジスタ値( = PR2 at Timer2) volatile int myDuty; //PWM出力ON時間に相当するレジスタ値(= OC1RS at OC1) volatile float PS_T2 = 16; //タイマ2のプリスケール値 //タイマ2の設定 PLIB_TMR_Stop(TMR_ID_2); // Disable Timer PLIB_TMR_ClockSourceSelect(TMR_ID_2, TMR_CLOCK_SOURCE_PERIPHERAL_CLOCK); // Select clock source PLIB_TMR_PrescaleSelect(TMR_ID_2, TMR_PRESCALE_VALUE_16); // Select prescalar value PLIB_TMR_Mode16BitEnable(TMR_ID_2); // Enable 16 bit mode PLIB_TMR_Counter16BitClear(TMR_ID_2); // Clear counter //PWM周期 //PR(PRレジスタ値) = Fpbclk(ペリフェラルバスクロック周波数)/Fpwm(PWM周波数)/タイマプリスケール値 - 1; myPR = (int)(100000000/Freq/PS_T2 -1); PLIB_TMR_Period16BitSet(TMR_ID_2, myPR); //Set period PLIB_TMR_Start(TMR_ID_2); //OC5モジュールの設定 PLIB_OC_ModeSelect(OC_ID_5, OC_COMPARE_PWM_EDGE_ALIGNED_MODE); PLIB_OC_BufferSizeSelect(OC_ID_5, OC_BUFFER_SIZE_16BIT); PLIB_OC_TimerSelect(OC_ID_5, OC_TIMER_16BIT_TMR2); PLIB_OC_FaultInputSelect(OC_ID_5, OC_FAULT_DISABLE); PLIB_OC_Buffer16BitSet(OC_ID_5, 0); myDuty = (int)(PR2 * Duty); //OC1RS = (int)(PR2 * Duty); PLIB_OC_PulseWidth16BitSet(OC_ID_5, myDuty); } void ClosePWM(void) { PLIB_TMR_Stop(TMR_ID_2); } void Do_C4(void) //第四オクターブ ド //C4 { BuzFreq(261.63,0.5);//ド //261.63Hz } void Re_D4(void) //第四オクターブ レ //D4 { BuzFreq(293.67,0.5); //レ //293.67Hz } void Mi_E4(void) //第四オクターブ ミ //E4 { BuzFreq(329.63,0.5); //ミ //329.63Hz } void Fa_F4(void) //第四オクターブ ファ //F4 { BuzFreq(349.23,0.5); //ファ //349.23Hz } void Re_D6(void) { BuzFreq(800,0.5); //レ //587.34Hz // BuzFreq(392.00,0.5); //ファ //349.23Hz } void _SoL1(void) { BuzFreq(392.00,0.5); //ファ //349.23Hz } void La_A4(void) //第四オクターブ ラ //A4 { BuzFreq(440.00,0.7); //ラ //440.00Hz } void La_sharpA4(void) //第四オクターブ #ラ(嬰イ) //A#4 { BuzFreq(466.16,0.7); //ラ //466.16Hz } void Si_B4(void) //第四オクターブ シ //B4 { BuzFreq(493.88,0.4); //シ //493.88Hz } void Do_C5(void) //第五オクターブ ド //C5 { BuzFreq(523.23,0.5); //ド //523.23Hz } void Re_D5(void) //第五オクターブ レ { BuzFreq(587.34,0.5); //レ //587.34Hz } void noSound(void) { ClosePWM(); delay_ms(50); } // ***************************************************************************** // ***************************************************************************** // Section: Global Data Definitions // ***************************************************************************** // ***************************************************************************** // ***************************************************************************** /* Application Data Summary: Holds application data Description: This structure holds the application's data. Remarks: This structure should be initialized by the APP_Initialize function. Application strings and buffers are be defined outside this structure. */ APP_DATA appData; // ***************************************************************************** // ***************************************************************************** // Section: Application Callback Functions // ***************************************************************************** // ***************************************************************************** /* TODO: Add any necessary callback funtions. */ // ***************************************************************************** // ***************************************************************************** // Section: Application Local Functions // ***************************************************************************** // ***************************************************************************** /* TODO: Add any necessary local functions. */ // ***************************************************************************** // ***************************************************************************** // Section: Application Initialization and State Machine Functions // ***************************************************************************** // ***************************************************************************** /******************************************************************************* Function: void APP_Initialize ( void ) Remarks: See prototype in app.h. */ void APP_Initialize ( void ) { /* Place the App state machine in its initial state. */ appData.state = APP_STATE_INIT; /* TODO: Initialize your application's state machine and other * parameters. */ } /****************************************************************************** Function: void APP_Tasks ( void ) Remarks: See prototype in app.h. */ void APP_Tasks ( void ) { T4 = 750; // T4 = 60 * 1000 / 80; //四分音符の時間(長さ) T4 = 750 [msec] /* Check the application's current state. */ switch ( appData.state ) { /* Application's initial state. */ case APP_STATE_INIT: { // へ長調 //固定ド唱法 //第1行: うさぎ追いし かの山 ----------------------------------------------------------- //-----第一小節 Fa_F4(); //ファ delay_ms(T4); //四分音符長さ noSound(); Fa_F4(); //ファ delay_ms(T4); //四分音符長さ noSound(); Fa_F4(); //ファ delay_ms(T4); //四分音符長さ noSound(); //------第二小節 _SoL1();//ソ delay_ms(1125);//付点付四分音符長さ // delay_ms(T4*1.5);//付点付四分音符長さ noSound(); La_A4(); //ラ delay_ms(T4/2); //八分音符長さ noSound(); _SoL1();//ソ delay_ms(750); // delay_ms(T4); //四分音符長さ noSound(); //-------第三小節 La_A4(); //ラ delay_ms(T4); //四分音符長さ noSound(); La_A4(); //ラ delay_ms(T4); //四分音符長さ noSound(); La_sharpA4(); //シ (#ラ) delay_ms(T4); //四分音符長さ noSound(); //--------第四小節 Do_C5(); //ド delay_ms(T4*2); //二分音符長さ noSound(); delay_ms(T4); //四分休符 //第2行 こぶな釣りし かの川 --------------------------------------------------------- //--------第一小節 La_sharpA4(); //#ラ delay_ms(T4); noSound(); Do_C5(); //ド delay_ms(T4); //四分音符長さ noSound(); Re_D5(); //レ delay_ms(T4); //四分音符長さ noSound(); //---------第二小節 La_A4(); //ラ delay_ms(T4*1.5);//付点付四分音符長さ noSound(); La_sharpA4(); //シ (#ラ) delay_ms(T4/2); //八分音符長さ noSound(); La_A4(); //ラ delay_ms(T4);//付点付四分音符長さ noSound(); //----------第三小節 _SoL1();//ソ delay_ms(750); // delay_ms(T4);//付点付四分音符長さ noSound(); _SoL1();//ソ // while(1); delay_ms(750); // delay_ms(T4);//付点付四分音符長さ noSound(); Mi_E4(); //第四オクターブ ミ //E4 delay_ms(T4);//付点付四分音符長さ noSound(); //-----------第四小節 Fa_F4(); //ファ delay_ms(T4*2); //二分音符長さ noSound(); delay_ms(T4); //四分休符 //第3行 夢は今も めぐりて //-----------第一小節 _SoL1();//ソ delay_ms(T4/2);//八分音符長さ noSound(); Fa_F4(); //ファ delay_ms(T4/2); //八分音符長さ noSound(); _SoL1();//ソ delay_ms(T4);//四分音符長さ noSound(); Do_C4(); //ド delay_ms(T4);//四分音符長さ noSound(); //------------第二小節 Fa_F4(); //ファ delay_ms(T4/2); //八分音符長さ noSound(); _SoL1();//ソ delay_ms(T4/2);//八分音符長さ noSound(); La_A4(); //ラ delay_ms(T4);//四分音符長さ noSound(); La_A4(); //ラ delay_ms(T4);//四分音符長さ noSound(); //------------第三小節 La_sharpA4(); //シ (#ラ) delay_ms(T4/2); // 八分音符長さ noSound(); La_A4(); //ラ delay_ms(T4/2);//八分音符長さ noSound(); La_sharpA4(); //シ (#ラ) delay_ms(T4*1.5); //付点付四分音符長さ noSound(); Re_D5(); //レ delay_ms(T4/2); //八分音符長さ noSound(); //-----------第四小節 Do_C5(); //ド delay_ms(T4/2); //二分音符長さ noSound(); La_sharpA4(); //シ (#ラ) delay_ms(T4/2); //八分音符長さ noSound(); La_A4(); //ラ delay_ms(T4);//四分音符長さ noSound(); delay_ms(T4); //四分休符 //第4行 忘れがたき 故郷(ふるさと) //---------第一小節 Do_C5(); //ド delay_ms(T4); //四分音符長さ noSound(); Do_C5(); //ド delay_ms(T4); //四分音符長さ noSound(); Do_C5(); //ド delay_ms(T4); //二分音符長さ noSound(); //----------第二小節 Fa_F4(); //ファ delay_ms(T4*1.5); //付点付四分音符長さ noSound(); _SoL1();//ソ // while(1); delay_ms(T4/2);//八分音符長さ noSound(); La_A4(); //ラ delay_ms(T4);//四分音符長さ noSound(); //----------第三小節 La_sharpA4(); //シ (#ラ) delay_ms(T4); //四分音符長さ noSound(); La_sharpA4(); //シ (#ラ) delay_ms(T4); //四分音符長さ noSound(); _SoL1();//ソ while(1); delay_ms(T4);//四分音符長さ noSound(); //-----------第四小節 Fa_F4(); //ファ delay_ms(T4*2); //二分音符長さ noSound(); delay_ms(T4); //四分休符 ///-------------------------------------------------------------------------------- delay_ms(3000); break; } /* TODO: implement your application state machine.*/ /* The default state should never be executed. */ default: { /* TODO: Handle error in application's state machine. */ break; } } } /******************************************************************************* End of File */ //以下、system_init.c //----------------------------------------------------------------------------------- /******************************************************************************* System Initialization File File Name: system_init.c Summary: This file contains source code necessary to initialize the system. Description: This file contains source code necessary to initialize the system. It implements the "SYS_Initialize" function, configuration bits, and allocates any necessary global system resources, such as the systemObjects structure that contains the object handles to all the MPLAB Harmony module objects in the system. *******************************************************************************/ // DOM-IGNORE-BEGIN /******************************************************************************* Copyright (c) 2013-2014 released Microchip Technology Inc. All rights reserved. Microchip licenses to you the right to use, modify, copy and distribute Software only when embedded on a Microchip microcontroller or digital signal controller that is integrated into your product or third party product (pursuant to the sublicense terms in the accompanying license agreement). You should refer to the license agreement accompanying this Software for additional information regarding your rights and obligations. SOFTWARE AND DOCUMENTATION ARE PROVIDED AS IS WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION, ANY WARRANTY OF MERCHANTABILITY, TITLE, NON-INFRINGEMENT AND FITNESS FOR A PARTICULAR PURPOSE. IN NO EVENT SHALL MICROCHIP OR ITS LICENSORS BE LIABLE OR OBLIGATED UNDER CONTRACT, NEGLIGENCE, STRICT LIABILITY, CONTRIBUTION, BREACH OF WARRANTY, OR OTHER LEGAL EQUITABLE THEORY ANY DIRECT OR INDIRECT DAMAGES OR EXPENSES INCLUDING BUT NOT LIMITED TO ANY INCIDENTAL, SPECIAL, INDIRECT, PUNITIVE OR CONSEQUENTIAL DAMAGES, LOST PROFITS OR LOST DATA, COST OF PROCUREMENT OF SUBSTITUTE GOODS, TECHNOLOGY, SERVICES, OR ANY CLAIMS BY THIRD PARTIES (INCLUDING BUT NOT LIMITED TO ANY DEFENSE THEREOF), OR OTHER SIMILAR COSTS. *******************************************************************************/ // DOM-IGNORE-END // ***************************************************************************** // ***************************************************************************** // Section: Included Files // ***************************************************************************** // ***************************************************************************** #include "system_config.h" #include "system_definitions.h" #include "app.h" // **************************************************************************** // **************************************************************************** // Section: Configuration Bits // **************************************************************************** // **************************************************************************** //コンフィグ //----------------------------------------------------------------------- //DEVCFG0レジスタ #pragma config EJTAGBEN = NORMAL #pragma config DBGPER = ALLOW_PG2 #pragma config FSLEEP = OFF #pragma config FECCCON = OFF_UNLOCKED #pragma config BOOTISA = MIPS32 #pragma config TRCEN = OFF #pragma config ICESEL = ICS_PGx2 #pragma config JTAGEN = OFF //JTAG ポート Disable #pragma config DEBUG = OFF //---------------------------------------------------------------------- //DEVCFG1レジスタ #pragma config FNOSC = SPLL //PLL回路(システムPLL)選択 //システム発振回路 //内蔵FRC(8MHz)選択の場合:FNOSC = FRCDIV //Oscillator Selection Bits (Fast RC Osc w/Div-by-N (FRCDIV)) #pragma config FDMTEN = OFF //デッドマンタイマ OFF (Deadman Timer is disabled) //#pragma config DMTINTV = WIN_127_128 // DMT Count Window Interval (Window/Interval value is 127/128 counter value) #pragma config FSOSCEN = OFF // 副発振器OFF //Secondary Oscillator Enable (Disable SOSC) #pragma config IESO = OFF //ウェイクアップ時の2段速度スタートアップ // Internal/External Switch Over (Disabled) #pragma config POSCMOD = EC //HS: ハイスピードレゾネータモード // HS(High Speed Resonator Operation) Oscillator mode selected //EC: 外部発振器 //EC(External Clock Input Operation) mode selected // Primary Oscillator Configuration (Primary osc disabled) #pragma config OSCIOFNC = OFF //OSCCOピン出力無効 #pragma config FCKSM = CSECME //クロック発振:切替及びモニタ有効 //主発振器失陥でFRC(内蔵高速発振器)に切替 //FSCM(Fail Safe Clock Monitor)制御 #pragma config FWDTEN = OFF // ウォッチドックタイマ OFF //Watchdog Timer Disable //#pragma config WDTPS = PS1048576 // Watchdog Timer Postscaler (1:1048576) //#pragma config WDTSPGM = STOP // Watchdog Timer Stop During Flash Programming (WDT stops during Flash programming) //#pragma config WINDIS = NORMAL // Watchdog Timer Window Mode (Watchdog Timer is in non-Window mode) //#pragma config FWDTWINSZ = WINSZ_25 // Watchdog Timer Window Size (Window size is 25%) //-------------------------------------------------------------------------------------------------------------------- // DEVCFG2レジスタ //システムクロック:200MHz //ペリフェラル周波数://default: 100MHz //PBxDIVで8系統毎に設定変更可 //PBxDIV: PERIPHERAL BUS CLOCK DIVISOR CONTROL レジスタのPBDIV<6:0>: Peripheral Bus Clock Divisor Control ビットで設定 #pragma config FPLLRNG = RANGE_5_10_MHZ //PLL Input周波数入力範囲設定// System PLL Input Range (5-10 MHz Input) //8(= 24/3)MHz故 #pragma config FPLLIDIV = DIV_3 //PLL入力側での分周: 1/3 // PLL Input周波数 = 24MHz ÷ 3 = 8MHz // System PLL Input Divider (1x Divider) //#pragma config FPLLICLK = PLL_POSC //主発振回路選択 //内蔵FRC(8MHz)の場合はFPLLICLK = PLL_FRC// System PLL Input Clock Selection (POSC is input to the System PLL) #pragma config FPLLICLK = PLL_FRC //内蔵高速発振器選択 //★★★ バグ有 主発振回路選択の時、FPLLICLK = PLL_POSCではなくFPLLICLK = PLL_FRCを選択する。(at ver.1.33 XC32) #pragma config FPLLMULT = MUL_50 //PLL倍率:50倍 //8MHz x 50 = 400MHz //System PLL Multiplier (PLL Multiply by 50) #pragma config FPLLODIV = DIV_2 //PLL出力側での分周: 1/2 //システムクロック = 400MHz ÷ 2 = 200MHz #pragma config UPLLFSEL = FREQ_24MHZ //USBのPLL入力を 24MHz→12MHzに変換 // USB PLL Input Frequency Selection (USB PLL input is 12 MHz) #pragma config UPLLEN = ON //USBのPLL変換:イネーブル // USB PLL Enable (USB PLL is enabled) //-------------------------------------------------------------------------------------------------------------------------- //DEVCFG3レジスタ #pragma config USERID = 0xffff #pragma config FMIIEN = ON #pragma config FETHIO = ON #pragma config PGL1WAY = ON #pragma config PMDL1WAY = ON #pragma config IOL1WAY = ON #pragma config FUSBIDIO = ON /*** BF1SEQ0 ***/ #pragma config TSEQ = 0xffff #pragma config CSEQ = 0xffff // ***************************************************************************** // ***************************************************************************** // Section: Library/Stack Initialization Data // ***************************************************************************** // *****************************************************************************/ // ***************************************************************************** // ***************************************************************************** // Section: Driver Initialization Data // ***************************************************************************** // ***************************************************************************** //<editor-fold defaultstate="collapsed" desc="DRV_Timer Configuration"> // </editor-fold> // ***************************************************************************** // ***************************************************************************** // Section: System Data // ***************************************************************************** // ***************************************************************************** /* Structure to hold the object handles for the modules in the system. */ SYSTEM_OBJECTS sysObj; // ***************************************************************************** // ***************************************************************************** // Section: Module Initialization Data // ***************************************************************************** // ***************************************************************************** //<editor-fold defaultstate="collapsed" desc="SYS_DEVCON Configuration"> /*** System Device Control Initialization Data ***/ const SYS_DEVCON_INIT sysDevconInit = { .moduleInit = {0}, }; // </editor-fold> // ***************************************************************************** // ***************************************************************************** // Section: Static Initialization Functions // ***************************************************************************** // ***************************************************************************** // ***************************************************************************** // ***************************************************************************** // Section: System Initialization // ***************************************************************************** // ***************************************************************************** /******************************************************************************* Function: void SYS_Initialize ( SYS_INIT_DATA *data ) Summary: Initializes the board, services, drivers, application and other modules. Remarks: See prototype in system/common/sys_module.h. */ void SYS_Initialize ( void* data ) { /* Core Processor Initialization */ SYS_CLK_Initialize( NULL ); sysObj.sysDevcon = SYS_DEVCON_Initialize(SYS_DEVCON_INDEX_0, (SYS_MODULE_INIT*)&sysDevconInit); SYS_DEVCON_PerformanceConfig(SYS_CLK_SystemFrequencyGet()); SYS_PORTS_Initialize(); /* Initialize Drivers */ /*Initialize TMR0 */ DRV_TMR0_Initialize(); DRV_TMR0_Start(); /*Initialize OC0 */ DRV_OC0_Initialize(); DRV_OC0_Enable(); /* Initialize System Services */ /* Initialize Middleware */ /* Initialize the Application */ APP_Initialize(); } /******************************************************************************* End of File */ //以下、drv_oc_static.c //---------------------------------------------------------------------------- /******************************************************************************* OC Driver Functions for Static Single Instance Driver Company: Microchip Technology Inc. File Name: drv_oc_static.c Summary: OC driver implementation for the static single instance driver. Description: The OC device driver provides a simple interface to manage the OC modules on Microchip microcontrollers. Remarks: Static interfaces incorporate the driver instance number within the names of the routines, eliminating the need for an object ID or object handle. Static single-open interfaces also eliminate the need for the open handle. *******************************************************************************/ //DOM-IGNORE-BEGIN /******************************************************************************* Copyright (c) 2013 released Microchip Technology Inc. All rights reserved. Microchip licenses to you the right to use, modify, copy and distribute Software only when embedded on a Microchip microcontroller or digital signal controller that is integrated into your product or third party product (pursuant to the sublicense terms in the accompanying license agreement). You should refer to the license agreement accompanying this Software for additional information regarding your rights and obligations. SOFTWARE AND DOCUMENTATION ARE PROVIDED AS IS WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION, ANY WARRANTY OF MERCHANTABILITY, TITLE, NON-INFRINGEMENT AND FITNESS FOR A PARTOCULAR PURPOSE. IN NO EVENT SHALL MOCROCHIP OR ITS LOCENSORS BE LIABLE OR OBLIGATED UNDER CONTRACT, NEGLIGENCE, STROCT LIABILITY, CONTRIBUTION, BREACH OF WARRANTY, OR OTHER LEGAL EQUITABLE THEORY ANY DIRECT OR INDIRECT DAMAGES OR EXPENSES INCLUDING BUT NOT LIMITED TO ANY INCIDENTAL, SPECIAL, INDIRECT, PUNITIVE OR CONSEQUENTIAL DAMAGES, LOST PROFITS OR LOST DATA, COST OF PROCUREMENT OF SUBSTITUTE GOODS, TECHNOLOGY, SERVOCES, OR ANY CLAIMS BY THIRD PARTIES (INCLUDING BUT NOT LIMITED TO ANY DEFENSE THEREOF), OR OTHER SIMILAR COSTS. *******************************************************************************/ //DOM-IGNORE-END // ***************************************************************************** // ***************************************************************************** // Header Includes // ***************************************************************************** // ***************************************************************************** #include "peripheral/oc/plib_oc.h" // ***************************************************************************** // ***************************************************************************** // Section: Instance 0 static driver functions // ***************************************************************************** // ***************************************************************************** void DRV_OC0_Initialize(void) { /* Setup OC0 Instance */ PLIB_OC_ModeSelect(OC_ID_5, OC_COMPARE_PWM_EDGE_ALIGNED_MODE); PLIB_OC_BufferSizeSelect(OC_ID_5, OC_BUFFER_SIZE_16BIT); PLIB_OC_TimerSelect(OC_ID_5, OC_TIMER_16BIT_TMR2); PLIB_OC_FaultInputSelect(OC_ID_5, OC_FAULT_DISABLE); PLIB_OC_Buffer16BitSet(OC_ID_5, 0); PLIB_OC_PulseWidth16BitSet(OC_ID_5, 10); } void DRV_OC0_Enable(void) { PLIB_OC_Enable(OC_ID_5); } void DRV_OC0_Disable(void) { PLIB_OC_Disable(OC_ID_5); } void DRV_OC0_Start(void) { PLIB_OC_Enable(OC_ID_5); } void DRV_OC0_Stop(void) { PLIB_OC_Disable(OC_ID_5); } bool DRV_OC0_FaultHasOccurred(void) { return PLIB_OC_FaultHasOccurred(OC_ID_5); } /******************************************************************************* End of File */ //以下、drv_tmr_static.c //-------------------------------------------------------------------------------- /******************************************************************************* Timer Static Driver File File Name: drv_tmr_static.c Company: Microchip Technology Inc. Summary: Timer driver implementation for the static single instance driver. Description: The Timer device driver provides a simple interface to manage the Timer modules on Microchip microcontrollers. Remarks: None *******************************************************************************/ /******************************************************************************* Copyright (c) 2014 released Microchip Technology Inc. All rights reserved. Mirochip licenses to you the right to use, modify, copy and distribute Software only when embedded on a MTMRrochip mTMRrocontroller or digital signal controller that is integrated into your product or third party product (pursuant to the sublTMRense terms in the accompanying lTMRense agreement). You should refer to the lTMRense agreement accompanying this Software for additional information regarding your rights and obligations. SOFTWARE AND DOCUMENTATION ARE PROVIDED AS IS WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION, ANY WARRANTY OF MERCHANTABILITY, TITLE, NON-INFRINGEMENT AND FITNESS FOR A PARTTMRULAR PURPOSE. IN NO EVENT SHALL MTMRROCHIP OR ITS LTMRENSORS BE LIABLE OR OBLIGATED UNDER CONTRACT, NEGLIGENCE, STRTMRT LIABILITY, CONTRIBUTION, BREACH OF WARRANTY, OR OTHER LEGAL EQUITABLE THEORY ANY DIRECT OR INDIRECT DAMAGES OR EXPENSES INCLUDING BUT NOT LIMITED TO ANY INCIDENTAL, SPECIAL, INDIRECT, PUNITIVE OR CONSEQUENTIAL DAMAGES, LOST PROFITS OR LOST DATA, COST OF PROCUREMENT OF SUBSTITUTE GOODS, TECHNOLOGY, SERVTMRES, OR ANY CLAIMS BY THIRD PARTIES (INCLUDING BUT NOT LIMITED TO ANY DEFENSE THEREOF), OR OTHER SIMILAR COSTS. *******************************************************************************/ // ***************************************************************************** // ***************************************************************************** // Header Includes // ***************************************************************************** // ***************************************************************************** #include "framework/driver/tmr/drv_tmr_static.h" // ***************************************************************************** // ***************************************************************************** // Section: Instance 0 static driver functions // ***************************************************************************** // ***************************************************************************** void DRV_TMR0_Initialize(void) { /* Initialize Timer Instance0 */ /* Disable Timer */ PLIB_TMR_Stop(TMR_ID_2); /* Select clock source */ PLIB_TMR_ClockSourceSelect(TMR_ID_2, TMR_CLOCK_SOURCE_PERIPHERAL_CLOCK); /* Select prescalar value */ PLIB_TMR_PrescaleSelect(TMR_ID_2, TMR_PRESCALE_VALUE_256); /* Enable 16 bit mode */ PLIB_TMR_Mode16BitEnable(TMR_ID_2); /* Clear counter */ PLIB_TMR_Counter16BitClear(TMR_ID_2); /*Set period */ PLIB_TMR_Period16BitSet(TMR_ID_2, 0); } inline void DRV_TMR0_Start(void) { /* Start Timer*/ PLIB_TMR_Start(TMR_ID_2); } inline void DRV_TMR0_Stop(void) { // Stop Timer PLIB_TMR_Stop(TMR_ID_2); } inline void DRV_TMR0_CounterClear(void) { // Clear 16-bit counter value PLIB_TMR_Counter16BitClear(TMR_ID_2); } void DRV_TMR0_CounterValueSet(uint32_t value) { // Set 16-bit counter value PLIB_TMR_Counter16BitSet(TMR_ID_2, (uint16_t)value); } uint32_t DRV_TMR0_CounterValueGet(void) { // Get 16-bit counter value return (uint32_t) PLIB_TMR_Counter16BitGet(TMR_ID_2); } /******************************************************************************* End of File */ //以下、sys_ports_static.c //------------------------------------------------------------------------------- /******************************************************************************* SYS PORTS Static Functions for PORTS System Service Company: Microchip Technology Inc. File Name: sys_ports_static.c Summary: SYS PORTS static function implementations for the Ports System Service. Description: The Ports System Service provides a simple interface to manage the ports on Microchip microcontrollers. This file defines the static implementation for the Ports System Service. Remarks: Static functions incorporate all system ports configuration settings as determined by the user via the Microchip Harmony Configurator GUI. It provides static version of the routines, eliminating the need for an object ID or object handle. *******************************************************************************/ //DOM-IGNORE-BEGIN /******************************************************************************* Copyright (c) 2013 released Microchip Technology Inc. All rights reserved. Microchip licenses to you the right to use, modify, copy and distribute Software only when embedded on a Microchip microcontroller or digital signal controller that is integrated into your product or third party product (pursuant to the sublicense terms in the accompanying license agreement). You should refer to the license agreement accompanying this Software for additional information regarding your rights and obligations. SOFTWARE AND DOCUMENTATION ARE PROVIDED AS IS WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION, ANY WARRANTY OF MERCHANTABILITY, TITLE, NON-INFRINGEMENT AND FITNESS FOR A PARTICULAR PURPOSE. IN NO EVENT SHALL MICROCHIP OR ITS LICENSORS BE LIABLE OR OBLIGATED UNDER CONTRACT, NEGLIGENCE, STRICT LIABILITY, CONTRIBUTION, BREACH OF WARRANTY, OR OTHER LEGAL EQUITABLE THEORY ANY DIRECT OR INDIRECT DAMAGES OR EXPENSES INCLUDING BUT NOT LIMITED TO ANY INCIDENTAL, SPECIAL, INDIRECT, PUNITIVE OR CONSEQUENTIAL DAMAGES, LOST PROFITS OR LOST DATA, COST OF PROCUREMENT OF SUBSTITUTE GOODS, TECHNOLOGY, SERVICES, OR ANY CLAIMS BY THIRD PARTIES (INCLUDING BUT NOT LIMITED TO ANY DEFENSE THEREOF), OR OTHER SIMILAR COSTS. *******************************************************************************/ //DOM-IGNORE-END #include "system_config.h" #include "peripheral/ports/plib_ports.h" #include "peripheral/int/plib_int.h" void SYS_PORTS_Initialize(void) { //RD9を OC5に設定 TRISDbits.TRISD9 = 0; //RD9 出力ポートに設定 /* PPS Input Remapping */ //リマップ PLIB_PORTS_RemapOutput(PORTS_ID_0, OUTPUT_FUNC_OC5, OUTPUT_PIN_RPD9 ); //RD5にOC5を設定 } /******************************************************************************* End of File */
<動作結果>
圧電スピーカによる PIC32MX795F512LのPWM制御による 唱歌「ふるさと」を 録音したファイル(_*.aac)です。 PCで再生して聞いてください。。